Skip to content

Error codes

Every non-2xx response uses the same envelope:

{
  "error": {
    "code": "INVALID_RECIPIENT",
    "message": "Not a valid phone number in international format",
    "details": { "recipient": "12345" },
    "requestId": "req_3f2c9a..."
  }
}
  • Branch on code, not on message (messages may be reworded). Codes are stable within /v1; new codes may be added.
  • requestId is also returned in the X-Request-Id response header. Include it when contacting support. You can send your own X-Request-Id (8–100 chars [A-Za-z0-9._-]) to correlate logs.
  • details is code-specific (for VALIDATION_ERROR it is a list of { path, message, code }).
HTTPCodeMeaningRetry?
400VALIDATION_ERRORRequest body, query or path is invalidNo — fix the request
400IDEMPOTENCY_KEY_REQUIREDPOST /v1/messages without Idempotency-KeyNo
400INVALID_RECIPIENTRecipient is not a valid phone numberNo
400WEBHOOK_URL_REJECTEDURL not allowed (not HTTPS, private address, unresolvable)No
400SEGMENT_TOO_COMPLEXA segment rule took too long to evaluateNo — simplify the conditions
401UNAUTHENTICATEDMissing, invalid, revoked or expired API keyNo
403INSUFFICIENT_SCOPEAPI key lacks a scope (details.required)No
403FORBIDDENNot allowed (role, or inactive organization/project)No
403CSRF_REJECTEDDashboard request from an untrusted originNo
403INSTANCE_LIMIT_REACHEDPlan's instance limit reachedAfter upgrading / deleting
403QUOTA_EXCEEDEDPlan quota reached (monthly messages, projects, webhooks)After the period / upgrade
403FEATURE_NOT_AVAILABLEThe plan or project does not include the feature (details.feature: inbox, campaigns)After upgrading / enabling
403CONTACT_LIMIT_REACHEDPlan's contacts-per-project limit reachedAfter upgrading / erasing contacts
403CAMPAIGN_LIMIT_REACHEDPlan's limit of campaigns scheduled, running or paused at onceAfter one finishes
404NOT_FOUNDResource does not exist or belongs to another projectNo
409CONFLICTGeneric conflict (e.g. slug taken)No
409EXTERNAL_REFERENCE_TAKENAnother instance in the project has this externalReferenceNo
409IDEMPOTENCY_KEY_REUSEDSame key used with a different requestNo — use a new key
409IDEMPOTENCY_REQUEST_IN_PROGRESSSame key still being processedYes, shortly
409INSTANCE_STATE_CONFLICTOperation not possible in the instance's state (e.g. send to LOGGED_OUT)After fixing state
409QR_NOT_AVAILABLENo QR / pairing code pending (details.status)Yes, after connect
409MEDIA_NOT_READYMedia expired or about to expireRe-upload
409CAMPAIGN_STATE_CONFLICTAction not possible in the campaign's status (e.g. edit a running campaign)No
409CONTACT_OPTED_OUTThe contact opted out; an opt-in cannot be recorded for themNo — they can send START
413PAYLOAD_TOO_LARGEBody or file too largeNo
415UNSUPPORTED_MEDIA_TYPEFile type not allowed or content does not match itNo
429RATE_LIMITEDToo many requests (Retry-After header, details.retryAfterSeconds)Yes, after the delay
429BACKLOG_LIMIT_REACHEDToo many queued messages in the projectYes, after ~30 s
500INTERNAL_ERRORUnexpected error (logged with the request ID)Yes, with backoff and the same idempotency key
503SERVICE_UNAVAILABLETemporarily unavailableYes, with backoff

A resource that exists in another tenant always returns 404, never 403, so IDs cannot be probed.