Skip to main content

Error envelope

Non-2xx responses use:

Actual status-code behavior

Rate-limit headers

In 429, the backend sends:
  • X-RateLimit-Global
  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Retry-After
  • X-RateLimit-Retry-Policy
Important details:
  • X-RateLimit-Retry-After is returned in milliseconds.
  • The error body also includes error.detailed.retryAfterInSeconds.
  • The backend does not currently add the standard Retry-After header.

Retry guidance

Retry only when the failure is likely transient:
  • 429
  • transient 5xx
Do not blindly retry:
  • 400 INVALID_JSON_BODY
  • 401 INVALID_OR_MISSING_API_KEY
  • 403 MISSING_PERMISSION
  • 403 PROJECT_SUBSCRIPTION_REQUIRED
  • 403 PROJECT_BILLING_PAYMENT_REQUIRED
  • 403 API_KEY_MODE_MISMATCH

Idempotency

POST /messages, POST /messages/batch, and POST /otp accept Idempotency-Key. Current backend behavior:
  • Reusing the same key for the same logical operation reuses the stored result.
  • OTP idempotency mismatches return 400 INVALID_JSON_BODY.
  • The public API does not currently expose a dedicated idempotency conflict response.

Common real-world codes

  • INVALID_CONTENT_TYPE
  • INVALID_JSON_BODY
  • INVALID_OR_MISSING_API_KEY
  • MISSING_PERMISSION
  • BRAZILIAN_PHONE_NUMBER_REQUIRED
  • PROJECT_SUBSCRIPTION_REQUIRED
  • PROJECT_BILLING_PAYMENT_REQUIRED
  • PROJECT_MESSAGE_QUOTA_REACHED
  • PROJECT_WEBHOOK_LIMIT_REACHED
  • WEBHOOK_ENDPOINT_ALREADY_EXISTS
  • TEMPLATE_NAME_ALREADY_EXISTS
  • UNKNOWN_MESSAGE
  • UNKNOWN_TEMPLATE
  • UNKNOWN_WEBHOOK
  • UNKNOWN_LOG
  • RATE_LIMITED
  • MESSAGE_PROVIDER_ERROR
  • OTP_PROVIDER_ERROR
  • API_KEY_MODE_MISMATCH
  • INTERNAL_SERVER_ERROR