Errors
Every error the API can return, with its stable code and how to fix it. Branch on code; see the error shape.
| HTTP | Code | How to fix |
|---|---|---|
| 401 | api_key_missingNo API key | Send your key in the header Authorization: Bearer sk_live_… (or sk_test_…). |
| 401 | api_key_invalidInvalid API key | Copy the key again from Developers → API keys. Keys start with sk_live_ or sk_test_. |
| 401 | api_key_revokedKey revoked | Someone revoked this key. Create a new one in Developers → API keys. |
| 401 | api_key_expiredKey expired | The key passed its expiry date. Create a new one. |
| 402 | subscription_inactiveSubscription not active | Renew the workspace subscription in Billing. Reads keep working meanwhile. |
| 402 | quota_exceededAllowance used up | The plan's allowance for this period is used. Upgrade or add an add-on in Billing. entitlement names the allowance. |
| 403 | insufficient_scopeMissing permission | The key lacks the scope in required_scope. Create a key that has it. |
| 403 | api_access_not_in_planAPI not in plan | Live API access needs a plan that includes it. Test keys work on every plan. |
| 403 | workspace_suspendedWorkspace suspended | Contact support to reactivate the workspace. |
| 403 | capability_disabledCapability turned off | This capability is turned off for the workspace. Contact support. |
| 403 | test_mode_unsupportedNot in test mode | This request acts on real customer data and has no simulated version. Use a live key, or a separate workspace for staging. |
| 400 | invalid_jsonInvalid JSON | The body is not valid JSON. Check quotes and commas, and send Content-Type: application/json. |
| 422 | parameter_missingMissing parameter | param names the missing field; details lists all of them. |
| 422 | parameter_invalidInvalid parameter | param names the field; message says what is wrong with it. |
| 404 | resource_missingNot found | No object with that id in this workspace. Test-mode ids (msg_test_…) are readable only with a test key, and live ids only with a live key. |
| 404 | route_not_foundUnknown URL | Check the path and method against the API reference. All paths start with /v1/. |
| 405 | method_not_allowedWrong HTTP method | This URL exists but not with this method. See the API reference. |
| 413 | payload_too_largeBody too large | Send a smaller request body. |
| 422 | idempotency_key_reusedIdempotency-Key reused | A key belongs to one request. Use a new Idempotency-Key for a different body. |
| 409 | idempotency_in_progressSame request still running | The first request with this key has not finished. Retry in a second. |
| 422 | window_closed24-hour window closed | WhatsApp only delivers free-form messages within 24 hours of the customer's last message. Send an approved template instead; it reopens the conversation when they reply. |
| 422 | template_not_foundTemplate not found | Check the template name and language, or use its tpl_… id. |
| 422 | template_not_approvedTemplate not approved | Only templates WhatsApp approved can be sent. Wait for template.status_changed, or fix the rejection in Templates. |
| 422 | template_variables_mismatchWrong template variables | Send exactly one non-empty value per {{n}} in template.variables.body, in order. |
| 409 | recipient_not_consentedRecipient has not consented | This contact has not agreed to business messages. If you have their consent elsewhere, resend with "consent_confirmed": true (it is recorded). |
| 422 | recipient_opted_outRecipient opted out | The contact asked not to be messaged. Do not retry. |
| 422 | sender_not_configuredNo sending number | Connect a WhatsApp number in Settings → Channels, or pass a valid from. |
| 422 | sender_not_sendableNumber cannot send | reason says why (e.g. disconnected, token expired). Fix the number in Settings → Channels. |
| 422 | channel_errorWhatsApp rejected it | channel_error carries WhatsApp's own code and message. Look the code up in WhatsApp's error list. |
| 409 | send_outcome_unknownEarlier attempt may have been sent | A previous request with this Idempotency-Key got an unclear answer from WhatsApp. Check GET /v1/messages?reference=… before sending again. |
| 422 | channel_not_connectedChannel not connected | Connect the channel (or reconnect it) in Settings → Channels. param names the field that chose the channel. |
| 409 | resource_existsAlready exists | Another object already uses this unique value (a phone number, an email, a name). existing_id names it when we can: update that one instead, or use the upsert endpoint. |
| 409 | resource_in_useStill in use | Something still depends on this object (a running campaign uses the template, a message uses the file). details lists what. Finish or remove those first. |
| 409 | state_conflictNot allowed in the current state | The action does not fit the object's current state, e.g. resolving a conversation that is already resolved, or starting a campaign that already started. Read the object, check state / status, then decide. |
| 422 | assignee_invalidMember cannot take this conversation | Assign someone from GET /v1/members who can see the conversation's channel. Viewers and members without access to that number are refused. |
| 422 | media_invalidFile not accepted | WhatsApp limits each media type: images JPEG/PNG up to 5 MB, video MP4/3GPP up to 16 MB, audio up to 16 MB, documents up to 100 MB, stickers WebP up to 100 KB (500 KB animated). message says which rule failed. |
| 422 | flow_not_triggerableFlow cannot be started | Only a published flow whose trigger is "API / webhook" can be started through the API. Publish it, or change its trigger in the flow builder. |
| 422 | webhook_url_invalidWebhook URL not allowed | Use a public https:// URL. Private, local and cloud-metadata addresses are refused. |
| 422 | webhook_endpoint_limitToo many endpoints | Delete an endpoint you no longer use (10 per workspace). |
| 429 | rate_limitedToo many requests | Wait Retry-After seconds. Pace requests using the RateLimit-* headers on every response. |
| 500 | internal_errorServer error | Retry with the same Idempotency-Key. If it persists, contact support with the request_id. |
| 503 | platform_pausedSending paused | Outbound messaging is paused platform-wide for maintenance or an incident. Retry later. |
| 503 | service_unavailableTemporarily unavailable | Retry with backoff. |