Getting Started
Errors & Rate Limits
Stable error codes returned in the error.code field of the API envelope.
Error codes
| Code | HTTP | Description |
|---|---|---|
unauthorized |
401 | Missing or invalid credentials. |
invalid_credentials |
401 | client-id / client-secret do not match. |
invalid_token |
401 | OAuth bearer token expired or revoked. |
expired_credentials |
401 | The API credentials have expired. Create new credentials in Developer Tools. |
ip_not_whitelisted |
401 | Caller IP is not on the account whitelist (API key authentication). The message shows the IP Washeej sees. |
insufficient_scope |
403 | Token or key lacks the required scope. |
subscription_required |
403 | Active plan with API access is required. |
billing_blocked |
403 | WhatsApp Cloud billing is not eligible for this number. |
rate_limit_exceeded |
429 | More than 120 requests per minute for this account (one bucket shared by /v1 and /external-api). The response carries Retry-After: 60. |
not_found |
404 | Resource not found or not owned by the account. |
validation_error |
422 | Request parameters failed validation. |
duplicate_contact |
409 | Contact with this phone already exists. |
duplicate_external_id |
409 | A catalog item or knowledge entry with this external_id already exists. Use PATCH or the bulk upsert. |
feature_disabled |
403 | The account's plan does not include this API (for example the catalog and knowledge API). |
not_runnable |
409 | The data source cannot run now: a run is in progress or its column mapping is not saved. |
marketing_suppressed |
422 | Contact opted out of marketing messages. |
capability_error |
422 | Operation not supported on this channel type. |
feature_disabled |
403 | The channel type (Cloud / Device QR / Coexistence) is not available in the account plan or platform config. Returned as 503 when Embedded Signup is not configured on the platform. |
limit_reached |
403 | The plan's WhatsApp account quota (account_limit) is exhausted. POST /webhooks returns it as 422 when the account already has 10 webhook endpoints. |
limit_exhausted |
422 | The plan's contact limit is exhausted (POST /contacts). |
idempotency_key_required |
422 | POST /templates/send was called without an Idempotency-Key header. |
idempotency_key_invalid |
422 | Idempotency-Key is longer than 128 characters. |
idempotency_in_flight |
409 | A send with the same Idempotency-Key is still being processed. Retry later with the same key. |
idempotency_conflict |
409 | The Idempotency-Key was already used with a different request body. |
template_not_approved |
422 | The template is not approved by Meta for sending. |
template_api_cloud_only |
422 | Template send requires a Cloud API channel (not Device / QR). |
template_required |
422 | The customer care window is closed or unknown; send an approved template instead. |
duplicate_device |
409 | This phone number is already connected as a device channel. |
invalid_channel_type |
422 | Operation only applies to Device (QR) channels. |
unsupported_type |
422 | POST /devices only creates type=device. Cloud numbers use hosted onboarding sessions. |
return_url_not_allowed |
422 | return_url host is not among the redirect URIs registered on your developer app. |
gowa_error |
502 | The WhatsApp device service failed to process the request. Retry later. |
qr_failed |
422 | QR code generation failed for this device. |
pairing_failed |
422 | Pairing code generation failed — try the QR code instead. |
invalid_phone |
422 | Phone number could not be normalized or is invalid. |
user_error |
401 | Credentials did not resolve to an API user. |
send_failed |
422 | Upstream WhatsApp send failed; inspect message details / Meta error. |
exception |
500 | Unexpected server exception while processing the request. |
Rate limiting
120 requests / minute / account, shared by /v1 and /external-api. A 429 / rate_limit_exceeded response carries Retry-After: 60; wait at least that long and back off exponentially. The Device API (/device-api/v1) has a separate limit of 100 requests / minute (no Retry-After header). POST /oauth/token allows 10 requests / minute.
Every /v1, /external-api and /device-api/v1 response carries X-RateLimit-Limit (requests per minute), X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the window resets). Slow down before Remaining reaches 0.
Validation errors are always JSON 422 with error.code = "validation_error" and the failing fields in error.details.fields, whatever your Accept header. The same body also keeps the top-level message and errors keys for older clients.
Unexpected server errors never include internal details: the message gives a request id to quote to support. Today they are returned as {"remark":"exception","status":"error"} with HTTP 200 (legacy shape). Once announced, they will move to HTTP 500 with error.code = "server_error"; handle both.
Billing gate
billing_blocked when Meta payment eligibility for the WhatsApp number is not satisfied. Resolve billing in Meta Business Manager, then retry.
Marketing opt-out
marketing_suppressed when the contact opted out for that WhatsApp number. Do not retry the same MARKETING template until the contact opts back in; use UTILITY / AUTHENTICATION for transactional traffic instead.
Pagination
List endpoints return a pagination object with current_page, last_page, and total. Pass page and per_page (max 100 where documented).