PurifyAI

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:

http
Authorization: Bearer pk_live_YOUR_KEY

Also accepted, for clients that reserve the Authorization header for their own proxy:

http
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

text
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.
Keys are server-side credentialsA key carries your full API quota and is not scoped down. Do not ship one in a mobile app, a browser bundle, or anything a user can read — proxy through your own backend instead.

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

401
unauthorized
Missing, unknown, revoked, or belonging to a disabled account. Deliberately one message for all four — distinguishing them would tell an attacker which guesses were once real.
403
plan
The key is valid but the account is not on Agency. Upgrading is the fix; retrying is not.
Verifying a key without spending quotaGET /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.
PreviousQuickstartNext POST /v1/scrub