Sign inGet an API key
API reference

Errors

Status codes, error shapes and troubleshooting.

The API uses standard HTTP status codes. Authentication and validation errors share the shape below; other errors (for example 404 or a business-rule 422) return a simple message.

// authentication / rate limit
{ "error": { "code": "insufficient_scope", "message": "Key lacks scope: messages:send" } }

// validation
{ "error": { "code": "validation_failed", "message": "The to field is required.",
             "fields": { "to": ["The to field is required."] } } }

// other
{ "message": "Message not found." }

Status codes

StatusCodeMeaning / what to do
200 / 201 / 204—Success (204 has no body).
202—Message accepted and queued.
401unauthenticatedMissing or malformed key. Keys start with wk_.
401invalid_keyUnknown or revoked key.
401expired_keyKey passed its expiry date. Create a new one.
403insufficient_scopeKey lacks the required scope — see scopes.
403ip_not_allowedYour server IP isn’t in the key’s allow-list.
403workspace_suspendedWorkspace is not active. Contact support.
403api_disabledYour plan doesn’t include API access. Upgrade the plan.
404—Resource not found in your workspace.
422validation_failedInvalid input. See error.fields.
422—Business rule: no active number, 24-hour window closed, opted-out contact, plan/quota limit reached.
429rate_limitedSlow down; honour Retry-After.
5xx—Our fault. Retry with exponential back-off; safe for reads, check status before re-sending messages.

Common problems

SymptomLikely cause
422 “24-hour customer service window is closed”Free-form message to someone who hasn’t written in 24 h. Send an approved template.
422 “No active WhatsApp number found”No connected number is active, or from isn’t one of your phone_number_ids.
Message stays queuedBrief delay under load; if it persists check the number’s status in the dashboard.
Message failedRead error on the message — often an unapproved template, wrong parameters, or an invalid WhatsApp number.
Webhook signature mismatchUsing parsed/re-serialised JSON rather than the raw body, wrong secret, or the timestamp isn’t part of the signed string.