Authentication

Draft. Written from the repository's documents and code; not yet reviewed by the owner.

Every request to the tenant API (/v1/*) carries an API key as a bearer token:

curl https://YOUR-API-ADDRESS/v1/meters -H "Authorization: Bearer $PAYRUDDER_API_KEY"

A key looks like qk_test_<prefix>_<secret> or qk_live_<prefix>_<secret>. The console shows it once, when you create it on the app's API keys page; Payrudder keeps only a hash and cannot show it again. An app can have at most 10 active keys in each environment.

One key, one environment

qk_test_ keys act on the app's sandbox, qk_live_ keys on its live environment; a key never reaches the other one, and a key whose prefix disagrees with its environment is refused with 401. The two environments share nothing: customers, meters, plans, invoices and webhook endpoints are separate. See Test mode.

Roles

A key has a role that decides what it may do, so a key can be as small as the code that holds it needs:

Role May
admin everything the tenant API offers
billing customers, subscriptions, credits and invoices; read events, the catalogue and usage
read_only read everything (GET), change nothing
ingest_only send usage events (events:write) and nothing else: the key to put in a service that only reports usage
custom exactly the permissions chosen when the key was made

A permission is resource:action (customers:read, invoices:write, events:write, sandbox:write, ...). A GET under /v1/<resource> needs <resource>:read, any other method <resource>:write. audit:read (the audit log, GET /v1/audit-events) is held by admin keys and by a custom key given it on purpose; read_only does not have it, because the log names people and addresses. A request the key is not allowed to make is 403 with the key gateway.auth.permission_denied, and the message names the permission it lacked. Give each service the narrowest role that works.

Rotating and revoking

A key can also have a rate limit of its own, a share of your plan's limit for each kind of request: in the console give the key a Rate limit (% of plan) from 1 to 100 (or send rate_percent when you create it). A key at 20 may use a fifth of the limit and gets 429 with the key gateway.rate_limit.exceeded and a Retry-After header when that fifth is spent, even if your other keys have left room; the rest of the limit stays for them. Leave it empty and the key only draws on the whole limit, like today. A rotated key keeps its share.

Rotating a key (in the console, or POST /app/v1/apps/{id}/api-keys/{key_id}/rotate) makes a new key with the same role and environment and sets an end time on the old one, so you can deploy the new key before the old one stops: during that overlap both work, afterwards the old one is 401. Revoking a key stops it. Rotate when a key may have leaked and whenever someone who knew it leaves.

When a request is refused

Answer Key Meaning
401 the key is missing, wrong, revoked, past its end time, or belongs to the other environment
403 gateway.auth.permission_denied the key's role lacks the permission the route needs
403 gateway.auth.tenant_not_active the environment is not active: a live environment that has not gone live yet, or one that is suspended or banned (also when the operator banned the whole account)
403 gateway.auth.tenant_read_only the environment is frozen: reads still work, anything else is refused
421 gateway.region.wrong only on a deployment with regional gateways: the environment is served from another region. X-Payrudder-Region names it and, when the deployment knows it, X-Payrudder-Region-Url is the address of that region's gateway. Nothing was done with the request; send it there
429 gateway.rate_limit.exceeded too many requests; wait the number of seconds in Retry-After and try again
429 identity.auth.rate_limited the address you call from has had many keys or tokens refused in the last minute (30): it is turned away before any key is looked up, whatever it sends, until the minute passes. Check for a script that still uses a revoked or mistyped key; an IPv6 address counts as its whole /64

Rate limits depend on the tier of the account and are counted per class of route; usage events are counted per event, not per request, so batching does not get around them. See Errors for the error format.

Keep keys safe