Authentication

Every request to the verification API (except the public health check) must be authenticated with an API key.

Two key types: publishable and secret

Keys come in two scopes, following the Stripe/Clerk model. The scope decides which endpoints a key may call:

TypePrefixWhere it livesCan call
Publishablepk_…Client-side — safe to ship in the SDK / your frontendStart a verification (/verify), uploads (/upload), SDK config (/config), and minimal submission status (/status — state + reason, no PII)
Secretsk_…Backend only — never in client codeEverything a publishable key can, plus the full verification result + PII (/verifications/:id) and captured media (/verifications/:id/media/:kind)

Each scope also carries the environment dimension in its prefix:

PrefixTypeEnvironment
pk_test_PublishableStaging
pk_live_PublishableProduction
sk_test_SecretStaging
sk_live_SecretProduction

A key looks like pk_test_aB3dE5fG7hJ9kL1mN3pQ5rS7tU9vW1xY — the prefix plus 32 random alphanumeric characters.

Never ship a secret (sk_) key in your SDK, mobile app, or any client code. The publishable key in your frontend can only start verifications and poll minimal status; it can never read identity data. Fetch results from your backend with a secret key. A publishable key hitting a secret-only endpoint gets 403 secret_key_required.

Authenticating a request

Pass the full key as a Bearer token in the Authorization header:

shell
curl "https://identity.myaza.app/api/kyc/config" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

The key identifies your organization and its environment — there is no separate organization ID to send.

Creating and managing keys

API keys are managed in the dashboard under Settings → Organization → Developers → API Keys.

  • Pick the key type (Publishable or Secret) when creating a key. The environment selector in the dashboard header decides whether it's a _test_ (staging) or _live_ (production) key.
  • Secret keys are shown only once, at creation. Store the value immediately in a secrets manager — it cannot be retrieved again, only the prefix is displayed afterward.
  • Publishable keys can be viewed anytime in the dashboard — they're public by design (they ship in your frontend), so there's no secret to protect.
  • Creating or revoking a key requires the api_keys:create permission. Members without it see keys read-only.
  • Revoke a key the moment it may be compromised. Revocation is immediate — the next request with that key returns 401.

Creating and revoking keys emit the api_key.created and api_key.revoked webhook events so you can wire them into your own security auditing.

Errors

StatusBodyCause
401{ "error": "Missing or invalid Authorization header" }No Authorization: Bearer … header.
401{ "error": "Invalid API key" }Unknown or revoked key.
403{ "error": "secret_key_required" }A publishable (pk_) key was used on a secret-only endpoint (full result or media). Use a sk_ key from your backend.

See Errors for the full list.

Where each key is used

  • Publishable (pk_…) — the client SDKs, which take an apiKey and call the API from the user's device, plus any frontend code that starts verifications. Match the environment: pk_test_ with the SDK's staging environment, pk_live_ with production.
  • Secret (sk_…) — your backend reading results: GET /verifications/:id for the full result + PII and GET /verifications/:id/media/:kind for captured media. Keep it server-side only.

Best practices

  • Never put a secret key in client code. If a publishable key leaks it can only start verifications; a leaked secret key exposes identity data — treat it like a password.
  • Never commit a key to a public repository or paste it where it could be scraped. Revoke immediately if a key leaks.
  • Use _test_ keys in development and CI; reserve _live_ keys for production traffic.
  • Rotate keys periodically.
  • Scope keys per service or environment so you can revoke one without disrupting everything.