Skip to main content

Errors

Every error uses the same envelope, with an HTTP status and a stable machine-readable code:

{
"error": {
"code": "validation_failed",
"message": "to must be a phone number with 8-15 digits"
}
}

Treat code as the contract and message as human-facing text (it may change).

HTTP statuses​

StatusMeaningRetry?
400Malformed request or validation failureNo — fix the request
401Missing, invalid or revoked credentialsNo — fix the key
403Authenticated but not permitted (scope, number, IP)No — change key restrictions
404Object does not exist in your workspaceNo
409Conflict with current state (number paused, template not approved)No
429Rate limited (reserved — no hard limit is enforced today)Yes, with backoff
500Our faultYes, with backoff, then contact support

Codes​

CodeStatusWhere
idempotency_key_required400Sending without the header
validation_failed400Any invalid field
invalid_upload400Contact import file could not be parsed
unauthorized401Bad or missing token
scope_not_permitted403Key lacks the scope
ip_not_allowed403Request from outside the key's allowlist
number_not_allowed403Key is not bound to that number
message_not_found404Unknown message id in this workspace
template_not_found404Unknown template
number_not_found404Unknown number
number_not_active409Number is paused
template_not_approved409Template is not approved

Retrying safely​

  • Sending: always reuse the same Idempotency-Key when retrying. A retry returns the original message instead of sending twice.
  • Reading: retrying is always safe.
  • Everything else: retry 429/5xx with exponential backoff; never retry 4xx without changing the request.

Request ids​

Every response carries X-Request-Id. Quote it in support tickets — the dashboard logbook lets you look up the exact call by that id.