x-api-key header for clients that cannot set Authorization:
Key modes
The prefix tells you the mode; the API enforces it.
A missing, unknown or revoked key, or one whose prefix does not match its mode, answers
401 unauthorized. A live key answers 403 account_not_active on codes until the application is approved, and on every call while the application is rejected or suspended.
Key access
A key has full access, or custom access to what you grant it. You choose when you create the key: on Application settings → API keys, Create a key, under Access.- All products, the default: full access. The key sends and reads on every product, and any product added later. It never manages domains, the suppression list, templates or webhooks: only a key you choose it for does.
- Custom: a level per product. Verify is none, check only, or send and check. Notifications is none, read only, or send. Email is none, read only, send, or send and manage. Manage webhooks is a switch beside them. The key calls only what it was granted, and it must be granted something.
No key you create holds
notifications:templates, full access included: the three calls that write a template answer 403 insufficient_scope. Templates are written on Notifications → Templates; your key lists them and reads one in full. The key of a connected app holds notifications:templates.
email:inbound reads the email your receiving addresses got. It is opt-in on every key, full access included: turn on Read received email when you create the key. A key without it answers 403 insufficient_scope on those calls.
Tawked Chat has two scopes, both a connected app’s: chat:menus, the conversation menus a connected app adds to its customer’s application, and chat:attendant, the auto-attendant it sets up there. No key you create holds either, full access included: those calls answer 403 insufficient_scope, and your own menus are added on Chat → Conversation menus and your auto-attendant built on Chat → Auto-attendant. The key of a connected app holds chat:menus and chat:attendant.
A call outside the key’s access answers 403. The body is the same whatever was missing; the header names the scope the call needs:
- Access is set once. It cannot be changed after the key is created: create a new key with the access you need, then revoke the old one.
- Check-only keys created earlier are unchanged. They hold
verify:checkandnotifications:read: they check codes and read statuses and templates, and send on neither product. - Test keys. WhatsApp has no sandbox, so a custom test key can be granted Verify and Email only, and
/v1/whatsapp/...refuses every test key:403 insufficient_scopewhen its access does not cover the call,403 live_key_requiredotherwise. On Email a test key reads and sends in test mode, to the simulator addresses only; the management endpoints (domains, suppressions, metrics, templates, webhooks) answer it403 live_key_required. - Managing is chosen, never implied.
email:manageandwebhooks:manageare held only by a key someone chose them for: a full-access key, made before or after they existed, sends and reads but never manages. On the key’s page, choose Email Send and manage and Manage webhooks, on a live key. - A sending key limited to one domain holds
email:sendalone and sends from that verified domain only (403 key_domain_mismatchfrom another, or once the domain is removed); it reads only that domain’s messages. - Partner keys always have full access and cannot be narrowed.
Expiry and IP allowlists
Set at creation time, in the key’s Security card (Expiry, Restrict to IP addresses), and checked right after the key is recognised, before anything else:- Expiry: once
expires_atpasses, every call answers401 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.
The order of checks
Knowing the order helps you read an error. On every endpoint:- Per-key rate limit (
429 too_many_requests), checked before authentication. - Key recognised, then expiry, IP allowlist and the key’s access (
403 insufficient_scope). - Account and application state (
403 account_not_active). - Request shape (
400 invalid_json,400 invalid_request), channel and destination (422). - Sandbox gates, hourly caps and the protection guard (
429,403). - Balance (
402 insufficient_credits). - The send itself (
502 send_failed, refunded).