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:
A key belongs to one application. Create it in the console under the application’s Application settings → API keys, with Create a key; it is shown in full once. Store it in your secret manager, never in client-side code. Who creates and revokes keys: the account owner, and an admin or developer whose access covers the whole application. A member given only one product of the application does not see its keys. How Tawked works explains the roles.

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.
Each level is a scope, and a scope that sends includes the one that checks or reads: 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:check and notifications: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_scope when its access does not cover the call, 403 live_key_required otherwise. 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 it 403 live_key_required.
  • Managing is chosen, never implied. email:manage and webhooks:manage are 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:send alone and sends from that verified domain only (403 key_domain_mismatch from another, or once the domain is removed); it reads only that domain’s messages.
  • Partner keys always have full access and cannot be narrowed.
Narrow access does not make a key public. Every key is a server-side secret: never put one in a browser, a mobile app or any other client-side code.

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_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 the key’s access (403 insufficient_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.
Last modified on October 20, 2026