Errors

The one error envelope and the closed set of error codes.

On this page

Every refusal has the same shape, so error handling is one switch statement:

json
{ "code": "VALIDATION_ERROR", "title": "...", "description": "..." }

Branch on code. The title and description are for people and may change. A VALIDATION_ERROR also carries fields, and an INSUFFICIENT_PERMISSION names the missing scope in permission.

Codes

CodeStatusMeaning
UNAUTHENTICATED401No key, or the key is invalid, revoked or expired.
INSUFFICIENT_PERMISSION403The key lacks a scope (named in permission), or names a workspace outside its allowlist.
NO_ORGn/aThe key belongs to no business.
WORKSPACE_REQUIRED400The key reaches several workspaces and the call has no X-WTN-Workspace.
NOT_FOUND404Unknown id, or one in a workspace outside your key's reach (deliberately identical).
VALIDATION_ERROR400The body failed validation; fields names each bad field.
STATE_INVALID409The action is not valid in the current state (for example launching a campaign that is not ready; the description names the blocker).
CONFLICT409An Idempotency-Key was reused with a different body, or is in flight.
RATE_LIMITED429A quota is exhausted; Retry-After gives the wait in seconds.
DB_UNAVAILABLE5xxWe could not process the request safely. Retry with the same Idempotency-Key.
INTERNAL_ERROR5xxOurs to fix. Send us the request id and timestamp.
REQUEST_ERROR400, 413, 415Refused before a route: malformed JSON, body too large or unsupported content type.

App and launch codes

CodeStatusMeaning
DEVICE_AUTH_INVALID401Heartbeat: the device is unknown or the refresh token is wrong, expired or revoked. Call register again.
USER_HASH_INVALID401A userHash that does not verify, or a verified user addressed without one.
INSTALL_BLOCKED403The workspace blocked this device.
LAUNCH_SIGNATURE_REQUIRED403The campaign requires a signed launch and the visit had none.
LAUNCH_TOKEN_INVALID403One answer for expired, forged, wrong-campaign, revoked-key and replayed tokens. Mint a fresh one.
COLLECTION_PAUSED429The spend guard tripped; collection is paused.

Retry only when it can help: RATE_LIMITED (after Retry-After), DB_UNAVAILABLE and INTERNAL_ERROR (with the same Idempotency-Key). Everything else needs a change to the request.