Skip to main content
Every request carries an API key. Send it as a Bearer token, or in the x-api-key header for clients that cannot set Authorization:
Keys are created in the dashboard under Applications, then your application, then Keys, and shown once. Store them in your secret manager, never in client-side code.

Key modes

The prefix tells you the mode; the API enforces it. A live key on a sandbox-only account, or a revoked key, answers 401 unauthorized. A key that belongs to an application that is not approved yet answers 403 account_not_active.

Scopes

A key is full (the default) or check. A check-scoped key may only call check and GET /v1/verify/{id}; start, resend and cancel answer 403 insufficient_scope. Use it on a server that only ever confirms codes and never sends them. Partner keys are always full scope.

Expiry and IP allowlists

Set at creation time, checked right after the key is recognised and before anything else:
  • Expiry: once expires_at passes, every call answers 401 key_expired.
  • IP allowlist: exact IPs and CIDR ranges, IPv4 and IPv6. A caller outside the list gets 403 ip_not_allowed. Empty means every address.
Rotate keys by creating the new one first, deploying it, then revoking the old one. There is no window where both must be in the same request.

The order of checks

Knowing the order helps you read an error. On every endpoint:
  1. Per-key rate limit (429 too_many_requests), checked before authentication.
  2. Key recognised, then expiry, IP allowlist and scope.
  3. Account and application state (403 account_not_active).
  4. Request shape (400 invalid_json, 400 invalid_request), channel and destination (422).
  5. Sandbox gates, hourly caps and the protection guard (429, 403).
  6. Balance (402 insufficient_credits).
  7. The send itself (502 send_failed, refunded).
The Errors page lists every code.