Authentication
Every request carries an API key. There are no sessions, cookies or OAuth flows on the REST API.
Sending the key
Preferred — a bearer token:
Authorization: Bearer pk_live_YOUR_KEY
Also accepted, for clients that reserve the Authorization header for their own proxy:
X-Api-Key: pk_live_YOUR_KEY
If both are present, Authorization wins. A request with neither returns 401 with a WWW-Authenticate: Bearer header.
Key format
pk_live_<public-id>_<secret>
The first half identifies the key and is what the dashboard displays as the prefix. The second half is the secret. Send the whole string — splitting it yourself will fail.
How keys are stored
Only an HMAC of the secret half is stored. The plaintext exists in exactly one response — the one that created or rotated the key — and nowhere afterwards.
That has consequences worth planning for:
- Neither the dashboard nor support can recover a lost key. Rotate instead.
- A database dump does not yield working keys.
- Comparison is constant-time, so a key cannot be discovered by timing the endpoint.
Rotating and revoking
Rotate issues a replacement and invalidates the old secret immediately — there is no grace period, so deploy the new value before rotating, or accept a gap.
Revoke is permanent. Any integration presenting that key starts receiving 401 on the next request. Naming keys after the system that uses them is what makes this decision safe to take months later.
Failure responses
401unauthorized403planGET /api/v1/health needs no key and confirms the service is reachable. To check a key specifically, send a small PNG to /api/v1/scrub — a 401 distinguishes a bad key from an unreachable service, though a success does consume one unit of quota.