Skip to content

All errors share one shape — status is always false, error_code is stable and machine-readable:

{
"status": false,
"error_code": "UNAUTHORIZED",
"description": "Human-readable message"
}

Match on error_code, never on description (wording may change).

HTTP Code When
401 UNAUTHORIZED Missing or unrecognized credentials
401 INVALID_TOKEN JWT invalid, malformed or revoked
401 TOKEN_EXPIRED JWT past expiry
401 INVALID_API_KEY API key not found or hash mismatch
401 API_KEY_INACTIVE API key disabled
401 API_KEY_EXPIRED API key expired
401 INVALID_CREDENTIALS Wrong username/password
401 USER_NOT_ACTIVE Account suspended or inactive
401 IP_NOT_ALLOWED JWT was issued with an IP restriction and the client IP is not allowed (API keys have no IP allowlist)
401 SIGNATURE_REQUIRED Key requires HMAC but signature headers missing
401 INVALID_SIGNATURE HMAC signature failed verification
401 API_KEY_REQUIRED Strict integration endpoint requires X-API-Key; JWT is not accepted
403 FORBIDDEN Authenticated, but route or permission denied
403 NO_SMS_ACCESS SMS not configured on the account
403 CONFIG_ERROR Credentials incomplete — contact support
403 CROSS_TENANT_WORKSPACE X-Workspace-ID names a workspace you don’t own (or deleted)
403 NO_MAIN_WORKSPACE No live main workspace — contact support
403 WORKSPACE_NOT_AVAILABLE Target workspace deleted — use a live workspace
403 INTEGRATION_NOT_ENABLED Live strict integration sending is not enabled for this workspace
HTTP Code When
400 INVALID_BODY Malformed JSON body
400 INVALID_PARAMS Invalid query or path parameters
400 INVALID_TO Missing, malformed or overlong recipient phone number
400 INVALID_MESSAGE Missing/empty message, oversized body or over-10-segment SMS text
400 INVALID_SENDER Missing or invalid sender_id (3–11 ASCII alphanumeric characters, not starting with a number)
400 INVALID_SENDER_ID Strict integration endpoint received an invalid sender_id
400 TOO_MANY_RECIPIENTS Over 100 recipients
400 INVALID_MESSAGES /sms/send-individual body has no messages[] entries
400 TOO_MANY_MESSAGES /sms/send-individual has over 1000 entries
400 IDEMPOTENCY_KEY_REQUIRED /sms/send-individual missing required Idempotency-Key header
400 IDEMPOTENCY_KEY_REQUIRED Strict integration request is missing both Idempotency-Key and X-CIO-Idempotency-Key; exactly one is required
400 MULTIPLE_IDEMPOTENCY_KEYS Strict integration request sent both sources or repeated either header
400 INVALID_IDEMPOTENCY_HEADER Strict endpoint received a legacy or unsupported idempotency header
400 INVALID_IDEMPOTENCY_KEY Standard Idempotency-Key is over 128 characters/uses unsupported characters, or Customer.io’s key is not 1–1024 visible ASCII bytes
400 INVALID_WORKSPACE_HEADER X-Workspace-ID is not a positive integer
409 IDEMPOTENCY_KEY_REUSED Same Idempotency-Key was used with a different request body
409 IDEMPOTENCY_REQUEST_IN_PROGRESS Same Idempotency-Key is still processing; retry later
413 REQUEST_TOO_LARGE Strict integration wire body exceeds 32 KiB
415 UNSUPPORTED_MEDIA_TYPE Strict integration request is not application/json
422 DESTINATION_BLOCKED Destination is blocked; no SMS or completed claim was created
HTTP Code When
429 RATE_LIMIT_EXCEEDED Per-account rate limit hit
429 TOO_MANY_ATTEMPTS Login/2FA brute-force limit (includes Retry-After)
503 RATE_LIMIT_UNAVAILABLE Per-account limiter is temporarily unavailable; retry with the same idempotency key for /sms/send-individual

Details and recommended client behavior: rate limits.

HTTP Code When
404 NOT_FOUND Message or resource not found
500 INTERNAL_ERROR Server-side error
500 DB_ERROR Send request could not be queued — atomic rollback, safe to retry
500 IDEMPOTENCY_ERROR The server could not reserve an idempotency key; retry with the same key
503 SANDBOX_UNAVAILABLE Sandbox simulator is not enabled for sk_test_ sends
503 QUEUE_UNAVAILABLE SMS queue temporarily unavailable; retry shortly
503 INTEGRATION_GATE_UNAVAILABLE Strict live access could not be verified; retry with the same key
  • Retry 429 (after a delay) and 500 DB_ERROR (idempotent by design). Do not blind-retry 4xx — fix the request instead.
  • Alert on credit_blocked from balance, and use DLRs for the final outcome of messages already accepted by the API.
  • Re-authenticate on 401 TOKEN_EXPIRED / INVALID_TOKEN if using JWT.
  • Log error_code + description + the request ID from your HTTP client for support escalations.