Skip to content
SMSRay

Errors and codes

Errors use conventional HTTP status codes and one JSON shape, with a stable machine-readable code you can branch on.

Error shape

Every error response has a JSON body with a human-readable error and a stable code. Some errors add details: a list of field problems on validation errors, or an object such as { country, allowed }.

400 application/json
{
  "error": "Invalid request",
  "code": "invalid_request",
  "details": [
    { "path": ["to"], "message": "Required", "code": "invalid_type" }
  ]
}
422 application/json
{
  "error": "We don't deliver to India yet. This workspace can send to: Nepal.",
  "code": "destination_not_supported",
  "details": { "country": "IN", "allowed": ["NP"] }
}

The error text may change. Write your logic against code and the HTTP status.

Error codes

All v1 API error codes
HTTPcodeWhen
400invalid_requestValidation failed (details lists each problem), bad JSON, both or neither of text and templateId, or text over 6 segments.
400invalid_numberThe number can't receive SMS — for example a landline.
400invalid_variablesA template variable is missing, unknown, empty, over 100 characters or contains a line break.
401unauthorizedx-api-key missing or invalid.
402insufficient_balanceWorkspace balance is lower than the message cost. Top up at your plan rate.
403client_disabledThe API client that owns the key is disabled.
403workspace_pendingYour workspace has not been activated yet.
403workspace_suspendedPOST while the workspace is suspended.
403forbiddenThe message type is not allowed on your plan or workspace (for example promotional outside Enterprise).
403template_requiredThe text doesn't match an approved template of the same type, or the templateId isn't an approved template of this workspace.
404not_foundUnknown id, or a message that belongs to another API client.
409idempotency_conflictIdempotency-Key reused with a different body, or the first request is still running.
422destination_not_supportedValid number, but in a country your workspace can't send to yet. details: { country, allowed }. Show "We don't deliver to <country> yet", not "invalid number".
429rate_limitedA rate or OTP limit was hit. Wait for Retry-After seconds.
500server_errorUnexpected error on our side. Retry with backoff and the same Idempotency-Key.
503unavailableDelivery is temporarily unavailable. Nothing was charged; retry with backoff.
503sms_disabledThe SMS service is temporarily switched off. Retry later.

Key restriction codes

If an account owner sets restrictions on an API client in the dashboard, requests outside them get one of these:

API client restriction errors
HTTPcodeWhen
403type_not_allowedThe message type is outside the types allowed for this key.
403ip_not_allowedThe call came from an IP outside the key's allowlist.
403prefix_not_allowedThe number's prefix is outside the key's allowed prefixes.
429daily_capThe key reached its daily message cap.
429number_capToo many messages to one number in an hour.
429suspected_pumpingOTP traffic on this key looks like SMS pumping and the guard is set to block.

Answers that are not errors

A wrong OTP is a normal answer from POST /sms/otp/verify, returned with HTTP 200:

200 application/json
{ "success": true, "verified": false, "reason": "invalid_code" }
OTP verify reasons
reasonMeaning
invalid_codeThe code does not match. The attempt is counted.
too_many_attempts5 wrong attempts were made. Send a new code.
no_active_otpNo code was sent for this number and purpose, it expired, or it was already used.

Likewise, a message that ends as undelivered or failed is reported through its status, with a neutral error code such as delivery_timeout, not as an API error.

Handling errors

How to handle each class of error
StatusRetry?What to do
400, 403, 404NoFix the request, the key, the template or the workspace setup.
401NoCheck the key; it may have been rotated.
402After top-upAdd balance, then retry with the same Idempotency-Key.
409Yes, carefullyIf the first request is still running, wait 1 s and retry. Otherwise use a new key for a new message.
422NoTell the user you don't deliver to that country yet; details.allowed lists where you can.
429YesWait Retry-After seconds.
500, 503YesExponential backoff with jitter, same Idempotency-Key.