error string. Branch on that string, not on the HTTP status: 429 alone has seven meanings, and 403 has ten.
{ "error": "insufficient_credits", "message": "Insufficient credits", "balance_halalas": 0, "price_halalas": 9 }
message (a sentence for your logs, never for branching), status, balance_halalas, price_halalas, provider_code, fields, errors and used_by. Every response carries an X-Request-Id header. Log it, and quote it when you write to support.
By HTTP status
| HTTP | What it means | Codes |
|---|---|---|
| 400 | The request is malformed. | invalid_json, invalid_request, service_required |
| 401 | The key is not accepted. | unauthorized, key_expired |
| 402 | The balance cannot pay for this send. | insufficient_credits |
| 403 | The key or the application may not do this now. | ip_not_allowed, insufficient_scope, account_not_active, application_paused, live_key_required, whatsapp_not_enabled, email_early_access, template_not_managed, partner_suspended |
| 404 | The thing named does not exist for this key. | not_found, service_not_found |
| 409 | The thing exists, but its state refuses the call. | not_resendable, not_cancelable, no_whatsapp_number, number_disconnected, no_verified_domain, number_connected, application_archived, not_retryable, template_not_editable, template_in_use, chat_not_ready, attendant_no_draft, attendant_unpublished, sending_blocked, idempotency_in_progress, idempotency_key_reused |
| 410 | The endpoint is retired. | product_retired |
| 413 | The e-mail or the request is too large. | message_too_large, request_too_large |
| 422 | The JSON is fine, but its content is refused. | invalid_destination, unsupported_channel, the sandbox_* codes, the template codes, consent_opted_out, invalid_params, sender_not_verified, recipient_suppressed, attachment_invalid, attachment_type_blocked, attachments_too_large, menu_limit_reached, attendant_not_ready |
| 429 | A limit is reached. | too_many_requests, rate_limited, ip_rate_limited, spend_cap_reached, sandbox_quota_exceeded, resend_limit_reached, daily_cap_reached |
| 500 | Something broke on our side. | internal_error |
| 502 | The carrier, Meta or the mail service refused or failed the send. | send_failed |
| 503 | A service we depend on did not answer, or sending is paused. | templates_unavailable, storage_unavailable, email_paused, chat_unavailable |
The Retry column
- Yes: send the same request again, with the same
Idempotency-Key. Back off between tries. - Later: the same request works once something changes: time passes, the balance is topped up, a template is approved. Do not loop on it.
- No: change the request, the key or the setup first. Sending it again answers the same.
Shared by every endpoint
Checked in this order, before the endpoint’s own logic.| HTTP | error | Meaning | What to do | Retry |
|---|---|---|---|---|
| 429 | too_many_requests | Per-key rate limit exceeded (120 requests per minute, fixed 60-second window; 1,200 on the e-mail endpoints). Checked before authentication. | The window starts on the minute; the Retry-After header gives the seconds to it. Wait for the next minute, then spread your calls. | Later |
| 401 | unauthorized | Missing, unknown, revoked or mode-mismatched key, or an unknown or suspended partner. | Check that the header carries the whole key, and that the key is still listed on API keys. | No |
| 401 | key_expired | The key’s expires_at has passed. Checked right after the key is recognised. | Create a new key on API keys and replace it where it runs. | No |
| 403 | ip_not_allowed | The caller’s IP is outside the key’s ip_allowlist. | Call from an allowed address, or create a key with the new address. | No |
| 403 | insufficient_scope | The key’s access does not cover the call: a custom key that was not granted the product, or one that checks or reads where the call sends. The WWW-Authenticate response header names the scope the call needs. | Use a key with that access, or create one. Access cannot be changed on an existing key. | No |
| 400 | service_required | A partner key with no application (or service) in the request. | Pass your external_id as application. | No |
| 404 | service_not_found | A partner key, but application does not match any of that partner’s provisioned applications. | Provision the application first, or fix the id. | No |
| 403 | account_not_active | The application is not approved yet (codes only), is rejected, suspended or archived, or a partner disabled it; or the account is banned. | Read the application’s status in the console. A test key sends while the application is in review. | Later |
| 400 | invalid_json | The request body is not valid JSON. | Send a JSON body with Content-Type: application/json. | No |
| 400 | invalid_request | A required field is missing or malformed: to on start, id or code on check; a reference, client_ip, autofill or Idempotency-Key out of shape; to, template, params, header or buttons on a WhatsApp send, such as a header.document that is not an object or text beside document; to, subject (1 to 255 characters) or neither html nor text on an e-mail send. message says which. On a template write, fields names the refused fields and errors gives each one’s codes, such as headerSampleUnreachable for header_sample_url or headerFormatInvalid for header_format. | Fix the field message names. | No |
| 500 | internal_error | An unhandled server error. Quote the X-Request-Id. | Retry with backoff. If it persists, write to support with the X-Request-Id. | Yes |
Verify
The codes of/v1/verify/..., after the shared checks.
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 422 | unsupported_channel | start | Unknown channel, or one that is not live: whatsapp, for codes, until Tawked turns it on. | Omit channel, or send sms. | No |
| 422 | sandbox_unsupported_channel | start | A test key on a channel that cannot carry the [TEST] stamp (WhatsApp). | Test on SMS. | No |
| 422 | invalid_destination | start | Not an accepted Saudi mobile format. See Numbers, language and the SMS. | Ask the user for the number again; show them the format. | No |
| 422 | sandbox_unverified_destination | start | A test key, and the destination is not the phone the account owner verified at signup. | Send to the owner’s phone, or use a live key. | No |
| 429 | sandbox_quota_exceeded | start | The application’s lifetime sandbox cap of 10 sends is reached. | Move to the live key. | No |
| 429 | rate_limited | start, resend | The per-destination hourly cap is reached. Same status as too_many_requests, different meaning. | Tell the user to wait before asking for another code. | Later |
| 429 | ip_rate_limited | start, resend | The client_ip you passed sent more starts this hour than max_per_ip_per_hour allows. | Treat it as suspicious traffic from that address. | Later |
| 429 | spend_cap_reached | start, resend | Today’s charges plus this send would pass daily_spend_cap_halalas. | The cap resets at midnight, Riyadh time. Raise it under Verify → Settings if the traffic is real. | Later |
| 403 | application_paused | start, resend | Auto-paused by the protection guard after a spike in new destinations. The owner or an admin resumes it in the console. | Look at the traffic before you resume the application. | Later |
| 402 | insufficient_credits | start, resend | The prepaid balance is below the channel price. Nothing was sent. | Top up, and set a balance alert or auto top-up in the wallet. | Later |
| 502 | send_failed | start, resend | The delivery provider failed. The charge is refunded automatically; retry with the same Idempotency-Key. | Retry once or twice with backoff; the failed attempt released the key. | Yes |
| 404 | not_found | check, status, resend, cancel | Unknown id, or an id that belongs to another account or application. | Use the id that start answered, with a key of the same application. | No |
| 409 | not_resendable | resend | Already verified, failed, expired or canceled. The body carries the current status. | Start a new verification if the user still needs a code. | No |
| 409 | not_cancelable | cancel | Already in a terminal state. The body carries the current status. | Nothing: it is already over. | No |
| 429 | resend_limit_reached | resend | This verification already used its 3 resends. | Start a new verification. | No |
WhatsApp messages
The Tawked Notifications endpoints,/v1/whatsapp/..., after the shared checks, in this order.
| HTTP | error | Meaning | What to do | Retry |
|---|---|---|---|---|
| 403 | live_key_required | A test key. WhatsApp has no sandbox; use the application’s live key. | Send with the live key. | No |
| 403 | whatsapp_not_enabled | WhatsApp is turned off for this application. Contact support if that is a mistake. | Write to support. | No |
| 409 | no_whatsapp_number | No WhatsApp number is connected to this application yet. | The owner or an admin connects one on Notifications → Overview. | Later |
| 409 | number_disconnected | The number is attached but Meta does not report it as connected right now. | Notifications → Overview shows the number’s health and what to fix. | Later |
| 404 | not_found | GET /v1/whatsapp/messages/{id} with an id that is not this application’s, or a template_id that is not on the number’s WhatsApp Business Account. | Use the id the send answered, or an id from GET /v1/whatsapp/templates. | No |
| 422 | invalid_destination | Not an accepted Saudi mobile format. | Fix the number. | No |
| 422 | unknown_template | No template with that name (and language, when given) on the number’s WhatsApp Business Account. GET /v1/whatsapp/templates lists what exists. | Check the name and lang against the list. | No |
| 422 | template_not_approved | The template exists but Meta has not approved it. message carries Meta’s status. | Wait for approval, or fix and resubmit it on Notifications → Templates. | Later |
| 422 | template_category_not_allowed | An authentication template sent with a partner key. Partner keys send utility and marketing templates; the application’s own live key sends authentication ones. Also a template write in a category the key may not write. | Send it with the application’s own live key. | No |
| 422 | consent_opted_out | A marketing template to a recipient who asked this application to stop its marketing (they wrote STOP to the number, or turned off its offers in WhatsApp). Nothing was sent, recorded or charged; utility and authentication templates still reach them. | Stop sending them marketing. | No |
| 422 | unsupported_template | The template needs a video or location header, a button or component that takes a non-text parameter, mixes named and positional placeholders, or names a placeholder longer than 20 characters (Meta refuses to send it). Image and document headers are supported: send them with header.image.link and header.document.link. message says which. | Use a template the endpoint carries. See Sending messages. | No |
| 422 | invalid_params | A placeholder value is missing, empty, unexpected, too long or contains a control character, the template exists in several languages and lang was not given, an authentication template got buttons or a code that is not 4 to 15 letters or digits, or an image or document header is missing, not https or sent to a template that does not open with one. message names the placeholder or the field. | Fix the value message names. | No |
| 402 | insufficient_credits | The balance is below the WhatsApp message fee. The body adds balance_halalas and price_halalas. | Top up. | Later |
| 502 | send_failed | Meta refused the send or is unreachable. The body adds provider_code and message; the fee is refunded. | Read provider_code. Retry a transient failure with the same Idempotency-Key; fix the request for a permanent one. | Yes |
| 503 | templates_unavailable | Meta did not answer the read of the template list, or a template write. Nothing was sent, changed or charged; retry shortly. | Retry with backoff. | Yes |
Template writes
Creating, editing and deleting a template over the API are not open to a key you create, full access included:POST, PATCH and DELETE under /v1/whatsapp/templates answer it 403 insufficient_scope, and templates are written on Notifications → Templates. The key of a connected app holds notifications:templates; these are the codes those three calls answer it.
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 403 | template_not_managed | update, delete | The key did not create this template. It changes only the ones managed is true on. | Change only the templates the key created. | No |
| 409 | template_not_editable | update, delete | The template cannot be changed over the API as it stands. status says why: the template’s status when it is not APPROVED, REJECTED or PAUSED, META_SAMPLE for one of Meta’s own samples, or MEDIA_HEADER for a template that opens with a video or a location, which is edited in the console, or with an image or a document when the edit leaves out header_format. | Wait for Meta’s review to end; send header_format with the edit of an image or document template; edit a video or location template in the console. | Later |
| 409 | template_in_use | update, delete | Something still sends the template. used_by lists what: campaign, automation, store_notice. | The business stops it or gives it another template in the console first. | Later |
| 422 | template_refused | create, update, delete | Meta refused the template after Tawked’s own checks passed, or the key holds as many templates as it may. message says which. | Fix what message names. | No |
| 409 | idempotency_in_progress | create, update, delete | A request with this Idempotency-Key is still running. | Retry in a moment with the same key. | Yes |
| 409 | idempotency_key_reused | create, update, delete | This Idempotency-Key was already used for a different request. | Generate a new key for the new request. | No |
/v1/email/..., after the shared checks, in this order. See Sending email. Beyond a send in the original shape (one to string), a refusal names where it sits: field (to, cc, headers.List-Unsubscribe, a list’s parameter) and field_index; a batch’s index names the message. Something that goes wrong at the sending service after the 202 is the message’s failed status and an email.failed webhook, never an error answer: its error.code is send_failed, email_paused (the sending service refused it as paused), email_early_access, sender_not_verified, recipient_suppressed, queue_expired, account_not_active (the account or application could no longer send when it was due) or application_deleted, and its price is refunded. A pause after the 202 holds the message instead: it stays queued and charged, is sent if the pause lifts within 12 hours of its time, and otherwise fails with queue_expired, refunded once.
| HTTP | error | Meaning | What to do | Retry |
|---|---|---|---|---|
| 413 | request_too_large | The request body is larger than the server accepts, so it never arrived whole. Nothing was recorded or charged. | Send fewer or smaller files: at most 10 MiB together, and a batch within 10 MiB. | No |
| 422 | header_not_allowed | A custom header is one Tawked or the sending service sets (the body’s header names it), or breaks the one-click unsubscribe rules. Nothing was sent. | Leave the header out (use the field that sets it, such as reply_to), or fix the unsubscribe pair. | No |
| 422 | attachment_invalid | An attachment is malformed: its filename, content (not base64), content_type or content_id, or more than 10 files. | Fix the attachment the message names. | No |
| 422 | attachment_type_blocked | An attachment’s extension is one mail services refuse (an executable, a script, a shortcut, a disk image), or the file is a program whatever its name. | Zip the file, or send a link to it. | No |
| 422 | attachments_too_large | The attachments together are over 10 MiB once decoded. | Send fewer or smaller files, or a link. | No |
| 403 | live_key_required | A test (tk_test_) key on a management endpoint: domains, suppressions, metrics and templates are the account’s real objects, managed with the application’s live key. A test key sends, reads and cancels messages in test mode; a partner’s test key (tk_partner_test_) has no e-mail at all. | Use the application’s live key for the management endpoints; send and read with a test key in test mode. | No |
| 409 | idempotency_key_reused | This Idempotency-Key already sent a different message (other recipients, subject, body, reply-to, headers, tags, time or files), or a different batch, within the last 24 hours. Nothing was sent. | Use one key per message; generate a new key for the new one. | No |
| 409 | idempotency_in_progress | A send with this Idempotency-Key is still on its way. Nothing was sent again. | Retry in a moment with the same key. | Yes |
| 503 | service_unavailable | Tawked Email is holding every new send for a while, a rare platform state. Nothing was recorded or charged. | Send again later with the same Idempotency-Key. | Later |
| 403 | email_early_access | Tawked Email is early access; apply from the console. | Apply from the application’s Email area; Tawked’s team reviews each request and tells you. | Later |
| 503 | email_paused | Sending is paused for the account: after a high bounce or complaint rate, a sudden jump in volume with bounces or complaints above Tawked’s line, a pause at the sending service, or by Tawked’s team. Nothing was sent or charged. | Request a review from the application’s Email area, and check your recipient lists. | Later |
| 409 | no_verified_domain | The application has no verified sender domain yet. | Add a domain on Email → Setup and its one TXT record. | No |
| 422 | sender_not_verified | from.address is not on a verified domain of this application. | Send from an address on a verified domain, or check the domain’s records. | No |
| 422 | invalid_destination | A recipient is not a valid e-mail address; field and field_index say which, beyond the original shape. | Fix the address field and field_index point at. | No |
| 422 | recipient_suppressed | The one recipient of a send in the original shape is on the account’s suppression list. Nothing was recorded or charged. | Stop sending to it; an address that bounced by mistake can be removed on Email → Suppressed. | No |
| 413 | message_too_large | html and text together are over 512 KiB. | Shorten the message; link to large content instead of embedding it. | No |
| 422 | content_blocked | The message links to a host on Tawked’s list of blocked hosts (known phishing or malware); the body adds host. Nothing was sent or charged. | Remove the link to host. | No |
| 422 | batch_invalid | An item of a batch was refused, so nothing was sent; errors lists each refused item by its index. | Fix the messages errors lists and send the batch again, or send it with Tawked-Batch-Validation: permissive. | No |
| 429 | rate_limited | The account made its requests for this second: 10 a second at the default daily limit, for all its applications, keys and the SMTP relay together; a batch counts once. Nothing was recorded or charged; Retry-After: 1. | Send again after a second; spread a burst, or send it as a batch. | Yes |
| 503 | email_platform_busy | Tawked Email has reached today’s sending capacity across all accounts, a rare state. Nothing was recorded or charged; retry after the Retry-After seconds. | Send again once the Retry-After seconds pass. | Later |
| 429 | daily_cap_reached | The account sent its daily limit of e-mails (Riyadh time): 5,000 unless Tawked set another for the account. Nothing was recorded or charged. | Wait for midnight, Riyadh time, or ask for a higher limit from the application’s Email area. | Later |
| 402 | insufficient_credits | The balance is below what the message needs once this month’s free e-mails are used. The body adds balance_halalas and price_halalas. | Top up. | Later |
| 409 | message_not_scheduled | The message is no longer scheduled, so it cannot be rescheduled or canceled; the body adds its status. | Read the message: it was sent, failed or canceled already. | No |
| 403 | application_key_required | A partner key. Use the application’s own key: partner keys manage client applications through the Partner API. | Call with the application’s own live key. | No |
| 409 | email_access_required | The account has not asked for Email yet: ask from the application’s Email area in the console. | Ask for Email from the application’s Email area. | No |
| 409 | email_access_pending | The account’s request for Email waits for Tawked’s team. | Wait for Tawked’s team to answer the request. | Later |
| 409 | email_product_off | The application’s Email product is off: turn it on in the console. | Turn Email on for the application in the console. | No |
| 403 | key_domain_mismatch | A sending key limited to one domain sent from another (the message names the domain), or its domain was removed: it sends from that domain alone. | Send from the key’s domain, or use a key that is not limited. | No |
| 422 | test_mode_recipient | Test keys send only to the simulator addresses: delivered@, bounced@, complained@, suppressed@, delayed@, opened@ and clicked@sim.tawked.com (field, and field_index among several). | Send to a simulator address, or use the live key. | No |
| 429 | test_mode_limit_reached | Test mode sends at most 1000 e-mails a day for an application (Tawked’s limit). It starts again at midnight, Riyadh time. | Wait for midnight, Riyadh time. | Later |
| 404 | content_not_kept | The application keeps no copy of this message: turn previews on in the console (Email → Settings); a message sent before that has none. | Turn previews on under Email → Settings; later messages keep a copy. | No |
| 422 | domain_invalid | Not a domain name. | Send the domain name alone, such as acme.sa. | No |
| 422 | domain_public | A public mailbox’s domain (gmail.com, outlook.com and the like) cannot send: use the business’s own domain. | Add the business’s own domain. | No |
| 422 | domain_tawked | Tawked’s own domains cannot be added. | Add your own domain. | No |
| 409 | domain_taken | Another application holds this domain, verified. | Use another domain, or remove it from the other application. | No |
| 409 | domain_limit | The application holds its most domains: remove one first. | Remove a domain the application no longer sends from. | No |
| 503 | email_unavailable | The sending service cannot be reached now: nothing changed; try again later. | Try again in a few minutes. | Later |
| 409 | domain_not_verified | The domain is not verified yet: its defaults and its tracking wait until it is. | Add the domain’s records and verify it first. | No |
| 409 | tracking_unavailable | Open and click tracking cannot be switched on yet. | Leave tracking off for now. | No |
| 422 | tracking_subdomain_invalid | The tracking subdomain is not a DNS label (letters, digits and -, up to 63), or it is the return path’s. | Choose another label, such as links. | No |
| 409 | tracking_subdomain_taken | The tracking subdomain already has records that are not the tracking edge’s: choose another label. | Choose a label with no records of its own. | No |
| 422 | suppression_invalid_addresses | No address given is valid, or addresses is not a list. | Send valid e-mail addresses. | No |
| 422 | suppression_too_many | More than 1000 addresses in one call (Tawked’s limit). | Split the list into calls of 1,000. | No |
| 422 | suppression_lift_reason_required | A complaint is lifted with a reason: recipient_asked, reported_by_mistake or other with a note. | Send reason (and note with other). | No |
| 403 | suppression_team_only | Only Tawked’s team lifts this address: it complained again after a lift, the team suppressed it, or another application of the account did. | Ask Tawked’s support. | No |
| 409 | suppression_import_running | An import of this application is still running: one at a time. | Wait for the running import to finish. | Later |
| 429 | suppression_import_daily | Ten imports a day for an application (Tawked’s limit). | Import again tomorrow, or add the addresses with the API. | Later |
| 422 | suppression_import_invalid_file | The file is not a CSV file Tawked can read. | Send a CSV file. | No |
| 422 | suppression_import_too_large | The file is larger than an import takes. | Split the file. | No |
| 422 | template_not_found | No template of the application has this id or alias (field: "template.id"). | Use the id or alias of a template of this application. | No |
| 422 | template_not_published | The template has never been published: publish it, or send its draft with a test key ("version": "draft"). | Publish the template. | No |
| 422 | template_variable_missing | A variable the template needs has no value and no fallback (field: "template.variables.<KEY>"). | Send the variable, or give it a fallback. | No |
| 422 | template_variable_unknown | A variable the template does not declare. | Send only the variables the template declares. | No |
| 422 | template_variable_invalid | A value that is not a string or a number, or longer than 2000 characters. | Send a string or a number within the limit. | No |
| 422 | template_variables_invalid | template.variables is not an object (over SMTP: 550 5.7.1 template_variables_invalid). | Send variables as an object. | No |
| 422 | template_alias_invalid | The alias is not lowercase letters, digits, - and _, up to 64, or it is shaped like a uuid. | Use lowercase letters, digits, - and _. | No |
| 422 | template_invalid | The draft cannot be published: problems lists each (placeholder_undeclared, subject_empty, content_empty, html_too_large, from_not_application_domain). | Fix each problem problems lists, then publish. | No |
| 409 | template_limit | The application has 100 templates, the most it may have (Tawked’s limit). | Delete a template you no longer use. | No |
| 409 | template_alias_taken | Another template of the application has this alias. | Choose another alias. | No |
| 409 | template_no_draft | The template has no draft to publish. | Change the template first: a change makes a draft. | No |
| 404 | not_found | An id that is not this application’s: a message, a domain (a removed one too), a suppressed address, an import, a template or a version. | Use the id the API answered. | No |
Conversation menus
The Tawked Chat endpoints,/v1/chat/menus/..., after the shared checks, in this order. They answer a connected app’s key alone: a key you create, full access included, gets 403 insufficient_scope naming chat:menus, and your own menus are added on Chat → Conversation menus.
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 403 | live_key_required | all five | A test key. A connected app’s key is live. | Use the key the exchange answered. | No |
| 400 | invalid_request | create, update, delete | fields names every refused field and errors gives its codes. title: required, length, taken. url: required, http, host, length, reserved. icon: type, small, unreachable. Also a malformed Idempotency-Key. | Fix the field errors names. | No |
| 404 | not_found | get, update, delete | A menu id this connection did not make, whoever made it. | Use an id your connection’s create answered. | No |
| 409 | idempotency_in_progress | create, update, delete | A request with this Idempotency-Key is still running. | Retry in a moment with the same key. | Yes |
| 409 | idempotency_key_reused | create, update, delete | This Idempotency-Key was already used for a different request. | Generate a new key for the new request. | No |
| 409 | chat_not_ready | create, update, delete | reason says why: chat, the account has no Tawked Chat yet, or number, the application’s WhatsApp number is not in Tawked Chat yet. Nothing changed. | Tell the customer; try again once it is ready. | Later |
| 422 | menu_limit_reached | create | The application already has 10 menus, the customer’s own and every app’s. limit says how many. | Remove a menu first, or ask the customer to. | No |
| 503 | chat_unavailable | create, update, delete | Tawked Chat did not answer. Nothing changed. | Retry with backoff and the same Idempotency-Key. | Yes |
Auto-attendant
The Tawked Chat endpoints/v1/chat/attendant/..., after the shared checks, in this order. They answer a connected app’s key alone: a key you create, full access included, gets 403 insufficient_scope naming chat:attendant, and your own auto-attendant is built on Chat → Auto-attendant.
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 403 | live_key_required | all five | A test key. A connected app’s key is live. | Use the key the exchange answered. | No |
| 400 | invalid_request | draft, publish, state, settings | fields names every refused field and errors gives its codes. menu: required, not_object, too_large. enabled: required. mode, language: invalid. Also a malformed Idempotency-Key. A menu that breaks a rule is saved with its problems. | Fix the field errors names. | No |
| 409 | idempotency_in_progress | draft, publish, state, settings | A request with this Idempotency-Key is still running. | Retry in a moment with the same key. | Yes |
| 409 | idempotency_key_reused | draft, publish, state, settings | This Idempotency-Key was already used for a different request. | Generate a new key for the new request. | No |
| 409 | attendant_no_draft | publish | No draft was saved yet. | Save one with PUT /v1/chat/attendant/draft first. | No |
| 422 | attendant_not_ready | publish | The draft has problems; problems lists them as { code, choice_id, field, max }. Nothing was published. | Fix the draft and publish again. | No |
| 409 | attendant_unpublished | state | Switched on before any publish. | Publish a menu first. | No |
| 409 | chat_not_ready | state | reason is number: the application’s WhatsApp number is not in Tawked Chat. Nothing changed. | Tell the customer; try again once it is. | Later |
| 409 | sending_blocked | state | The number cannot send: reason is payment (an unpaid balance) or blocked. Nothing changed. | Tell the customer. | Later |
| 503 | chat_unavailable | state | Tawked Chat did not answer. Nothing changed. | Retry with backoff and the same Idempotency-Key. | Yes |
Partner API
The partner endpoints (/v1/partner/...) have their own ladder. Codes sent on behalf of an application meet the shared and Verify ladders above, where service_required, service_not_found and account_not_active are the partner-key cases; see Sending codes for an application.
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 429 | too_many_requests | all | Per-key rate limit exceeded (120 requests per minute). Checked before authentication. | Wait for the next minute. | Later |
| 401 | unauthorized | all | Missing, unknown or revoked key; a tk_live_ or tk_test_ key; or a partner account Tawked suspended. | Use the partner key from Clients → API and webhook. | No |
| 401 | key_expired | all | The key’s expires_at has passed. | Create a new partner key. | No |
| 403 | ip_not_allowed | all | The caller’s IP is outside the key’s allowlist. | Call from an allowed address. | No |
| 400 | invalid_json | every endpoint with a JSON body | The request body is not valid JSON. | Fix the body. | No |
| 400 | invalid_request | every endpoint with a body or filters | A field is missing or refused; fields names them. How fields names them. | Fix the fields named. | No |
| 404 | not_found | every endpoint with an external_id or another id | Not one of your applications, whether or not it exists under another partner. Also a delivery that is not yours. | Check the external_id. | No |
| 403 | partner_suspended | writes | Your partner account was suspended between the key check and the write. In practice the key already answers 401 unauthorized. | Write to support. | No |
| 403 | live_key_required | writes | A tk_partner_test_ key on a management write. The sandbox key reads and sends; use the live key to change anything. | Use the live partner key. | No |
| 409 | number_connected | archive | A WhatsApp number is attached; disconnect it first. | Disconnect the number, then archive. | No |
| 409 | application_archived | writes | The application is archived. Restore it first; reads still work. | Restore it, then write. | No |
| 409 | not_retryable | retry | Only a failed delivery can be retried; status says what this one is. | Nothing: a pending delivery runs on its own. | No |
| 503 | storage_unavailable | logo | The file store refused the write, so nothing was recorded. Retry shortly. | Retry with backoff. | Yes |
| 409 | idempotency_in_progress | writes | A request with this Idempotency-Key is still running. Wait for its answer, or retry in a moment. | Retry in a moment with the same key. | Yes |
| 409 | idempotency_key_reused | writes | This Idempotency-Key was already used for a different request. Use one key per business event. | Generate a new key for the new request. | No |
| 500 | internal_error | all | An unhandled server error. Quote the X-Request-Id. | Retry with backoff and the same Idempotency-Key. | Yes |
Partner invalid request fields
fields names what was refused, in your own spelling:
- Verify settings endpoint: the bare field names, or
verifyalone for an empty or unrecognised patch. - Provision and brand update:
verify.followed by the field name for a refused setting. - Metadata:
metadata.followed by the key for a refused tag, ormetadataalone for a wrong shape, on a write or on the list filter. - Logo:
logofor a missing, oversized or non-image file. - Webhook:
eventsfor an unknown event name;urlorsecret, which are set in the console only. - Feeds and logs:
cursor,since,eventorstatus. - Usage: no
fields;messagesaysfromandtomust be ISO dates. - Any write: a malformed
Idempotency-Keyis refused with amessage.
Webhook endpoints
The webhook endpoints by API,/v1/webhooks/..., after the shared checks; a live key with the explicit webhooks:manage.
| HTTP | error | Meaning | What to do | Retry |
|---|---|---|---|---|
| 403 | application_key_required | A partner key. Use the application’s own key: partner keys manage client applications through the Partner API. | Call with the application’s own live key. | No |
| 403 | live_key_required | A test key: webhook endpoints are the application’s real objects, managed by a live key. | Use the application’s live key. | No |
| 422 | webhook_event_unknown | An event the application’s products do not send, or the endpoint does not receive (field, and field_index in a list). | Send events the application’s products send. | No |
| 422 | not_https | The address is not https. | Use an https address. | No |
| 422 | credentials | The address carries a user name or a password. | Take the user name and password out of the address. | No |
| 422 | invalid_host | The address has no valid host name. | Fix the address. | No |
| 422 | ip_address | The address is an IP address: use a host name. | Use a host name. | No |
| 422 | private_host | The host is private or local, unreachable from the internet. | Use an address reachable from the internet. | No |
| 409 | endpoint_limit_reached | The application has five endpoints, the most it may have: delete one first. | Delete an endpoint first. | No |
| 409 | endpoint_off | The endpoint is off: turn it on first. | Turn the endpoint on first. | No |
| 409 | delivery_pending | The delivery is still being retried: only a final one (delivered or failed) is sent again. | Wait for its retries to end. | Later |
| 409 | delivery_erased | The received email this delivery carried was deleted: its delivery keeps its status but not its words, and is not sent again. | Nothing to send again. | No |
| 409 | replay_running | A replay of this endpoint is still running: one at a time. | Wait for the running replay to finish. | Later |
| 409 | idempotency_secret_not_replayable | This Idempotency-Key already made a secret, which is shown once and never again: the endpoint or the rotation exists; read it, or rotate again with a new key. | Read the endpoint, or rotate with a new key. | No |
| 404 | not_found | An endpoint, a delivery or a replay that is not this application’s. | Use the id the API answered. | No |
Received email
The received email endpoints,/v1/email/received/... and /v1/email/inbound-addresses, after the shared checks and live_key_required. They need a key that holds email:inbound (403 insufficient_scope names it); a forward needs email:send too, and answers every refusal of a send listed under Email.
| HTTP | error | Meaning | What to do | Retry |
|---|---|---|---|---|
| 404 | not_found | No received email of this application has that id: another application’s, one you deleted, one past the 30 days, or an attachment of another email. | Use an id from the list or the webhook. | No |
| 409 | received_not_ready | The email is still being read (status received). | Forward it once it is ready, a few seconds later. | Yes |
| 410 | received_content_gone | The stored copy behind the raw message, the attachment or the bodies is gone. | Read the email’s details; its content cannot be downloaded or forwarded. | No |
| 413 | forward_too_large | A forward carries at most 10 attachments and 10 MiB in all, a Tawked limit. | Download the files and send them yourself. | No |
| 422 | forward_risky_attachment | The email carries an attachment that could run a program; it is never forwarded. | Download what you need and send it yourself. | No |
| 403 | test_key_required | A live key on POST /v1/email/received/test, the simulated receive: a live key receives real mail at its addresses. | Call it with the application’s test key (tk_test_). | No |
Retired endpoints
| HTTP | error | Endpoints | Meaning | What to do | Retry |
|---|---|---|---|---|---|
| 410 | product_retired | /v1/messages, any method | The old messaging product is retired. The route answers this to every call, with or without a key. | Send WhatsApp templates with POST /v1/whatsapp/messages. | No |