Skip to content

Documentation

Build with Engage

Connect customer data, business events, and communication channels to build automated journeys with workflows and AI.

Errors

One shape for every failure, so you write one handler rather than guessing per endpoint.

{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed",
    "details": { "phone": "must be E.164, starting with +" }
  },
  "request_id": "req_4e1f222a0b72471f83cf"
}

Keep the request_id

It is logged on our side against the full stack trace. A support conversation that opens with the id is a two-minute answer; one that opens with “it failed yesterday afternoon” is an hour of searching.

Log it wherever you log the failure. It is the single most useful field in this envelope and the one most integrations discard.

401 and 403 are not interchangeable

401 means we do not know who you are — the credential is missing, malformed or revoked.

403 means we know exactly who you are and the answer is still no. An API key reaching outside its two paths gets this, and no amount of re-authenticating changes it.

Clients that collapse the two into “auth failed” end up re-authenticating in a loop against a permission problem, which looks from our side like a credential being brute-forced.

Every code

StatusCodeMeansDo
400invalid_requestA field failed validation.Read details — it names the offending fields. Do not retry unchanged.
400malformed_requestThe body was not readable JSON.A bug in the caller. Check serialisation and Content-Type.
401unauthorizedNo credential, or one that is not valid.Check the X-API-Key header. Do not retry — it will not become valid.
403forbiddenValid credential, refused. Usually a key reaching outside /v1/events or /v1/customers.Fix the call, or use the dashboard. Retrying returns the same.
403feature_not_availableThe workspace plan does not include this capability at all - campaigns, the API, webhooks, workflows or the AI.Upgrade the workspace plan. Retrying returns the same. GET /v1/entitlements says what the plan includes.
409plan_limit_reachedThe capability is on the plan and its allowance is full - active workflows, team seats, connected numbers, templates or monthly events.Remove or disable one, or upgrade. The message names the allowance; GET /v1/entitlements gives the number.
404not_foundNo such record in your workspace.Note the scope: a record in another workspace is not found, not forbidden.
405method_not_allowedRight path, wrong verb.The Allow header lists what would work.
409conflictSomething unique already exists.Usually a duplicate. Treat as already-done rather than failed.
415unsupported_media_typeA body that was not JSON.Set Content-Type: application/json.
422unprocessableWell-formed, and impossible in the current state.Read the message. Retrying without changing something will not help.
429rate_limitedToo many attempts.Wait for Retry-After. See Rate limits.
500internal_errorOur fault.Safe to retry with backoff. Quote request_id if you contact support.

What to retry

Retry: 500, 502, 503, network failures, and 429 after Retry-After. Use exponential backoff.

Do not retry: any other 4xx. The request will not become valid by being sent again, and a client retrying a validation error forever is indistinguishable from an attack.

Retry safely by sending an idempotency key

A timeout tells you nothing about whether the request arrived. With an idempotency key you can retry without wondering — the second call returns the first result rather than recording a second event and sending a second WhatsApp message.

Next

Rate limits →

What is limited today, what is not, and how to behave when you meet one.