Skip to content

Get started

Errors, rate limits and CORS

Every error is a JSON object with an error message and a standard HTTP status. Simple actions that succeed return {"ok": true}.

What does an error look like?

{ "error": "API key is read-only" }

The error text is meant for people and logs. Branch on the HTTP status in your code, and treat the message text as informational. Unknown fields in request bodies are ignored rather than rejected.

Some errors add fields:

  • 402 adds "code": "payment_required".
  • Errors from Meta on the Cloud API channel endpoints add meta_code, meta_subcode and meta_title when Meta provides them.
  • 502 from Start a conversation adds the conversation that was created before the send failed.
  • A path that does not exist returns 404 with {"error": "not found", "code": "not_found"}, so you can tell a wrong URL from a missing resource.

Which status codes are used?

StatusWhenExample error
400Invalid input or a malformed id; session request without a workspace.invalid conversation id, message body is required, workspace required (X-Tenant-ID)
401Missing, wrong, revoked or expired credentials.invalid or expired API key, unauthorized
402Subscriptions are enforced and the workspace has none.subscription required
403Not allowed for this key or user.API key is read-only, API keys cannot administer workspaces, API key belongs to a different workspace, admin required, forbidden
404The resource does not exist in this workspace (or is not visible to an agent).conversation not found, contact not found
409Conflicts with the current state.whatsapp is not connected, a contact with this phone number already exists
413A request body is too large (Meta callback).payload too large
429Too many attempts on a rate-limited endpoint.too many attempts, please wait a minute and try again
500Unexpected server error, or an error from WhatsApp or Meta while sending.varies
502WhatsApp or Meta rejected an upstream call.meta rejected the template request: …
503A dependency is down (health check returns status: "degraded"), or the guided Meta signup is not configured on the server.customer signup is awaiting platform configuration

405 and 422 are not used.

What should I retry?

StatusRetry?
500, 502, 503Yes, with exponential backoff (for example 1 s, 2 s, 4 s, up to a few attempts).
429Yes, after the number of seconds in Retry-After.
409 whatsapp is not connectedOnly after the connection is back (check QR session status).
400, 401, 402, 403, 404No. Fix the request, key or permissions first.

A send that failed with 500 may in rare cases still have reached WhatsApp. Before retrying a send, check the latest messages of the conversation.

Are there rate limits?

Only public endpoints are rate limited, per client IP address, with a sliding window kept in memory. These are the sign-in and email endpoints (the website’s contact form has its own limit):

EndpointsLimit
POST /api/auth/register, /login, /reset-password, /verify-email, /google/confirm10 per minute, shared by these endpoints
POST /api/auth/forgot-password, /resend-verification5 per minute, shared by these endpoints
GET /api/auth/google/start, /google/pending20 per minute, shared by these endpoints

Over the limit you get 429 with too many attempts, please wait a minute and try again and a Retry-After header in seconds. There are no X-RateLimit-* headers.

Requests authenticated with API keys are not rate limited today. Limits may be added later, so handle 429 and Retry-After everywhere, and avoid tight polling loops: use webhooks or live events instead.

Which list endpoints are capped?

No list endpoint has pagination except messages. Lists return at most:

EndpointCap
List conversations30 most recent
List messageslimit up to 100 per page (default 50), paginated
Contacts, templates, knowledge articles500 newest
Webhooks10 per workspace
Template syncFirst page from Meta (up to 100)

How does CORS work?

The API answers OPTIONS preflight requests with 204 and allows the methods GET, POST, PUT, PATCH, DELETE, OPTIONS and the request headers Content-Type, Authorization and X-Tenant-ID. No response headers are exposed to scripts beyond the defaults. Never use API keys from browser code; call the API from your server.