Getting Started

Errors & Rate Limits

Stable error codes returned in the error.code field of the API envelope.

Error codes

CodeHTTPDescription
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

Cloud API payment eligibility Outbound Cloud sending may return 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 MARKETING template sends may return 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).