Skip to main content

Error codes

Every failure returns one of these codes. They are stable strings: branch on them.

Only five codes are retryable

Out of the whole catalogue, exactly five mean "try again and it might work":

CodeHTTPWhy it can succeed on a retry
RATE_LIMITED429You are going too fast. Back off and retry.
PIN_RATE_LIMITED429Too many PIN requests for this number. Wait before retrying.
INTERNAL_ERROR500Something failed on our side. Retry with backoff.
FRAUD_CHECK_UNAVAILABLE503The anti-fraud check could not be completed. Nothing was consumed: retry.
ANTIFRAUD_SCRIPT_UNAVAILABLE503We could not fetch the protection script. Retry before serving the page.

Everything else below is retryable: false. Retrying it will fail identically.

Authentication and access

CodeHTTPWhat it means
UNAUTHENTICATED401No token, or not a valid one.
CREDENTIAL_REVOKED401The token existed and has been withdrawn. Contact the operator team.
IP_NOT_ALLOWLISTED403Your source address is not registered. The response tells you the address we saw: compare it with what you registered.
ABILITY_NOT_GRANTED403Your credential is valid but not permitted for this operation.
SERVICE_NOT_FOUND404No such service, none you have access to, or one that has been removed from the catalogue. The three are deliberately indistinguishable.
SERVICE_NOT_ON_SHORT_CODE422The service is not on the short code your credential is bound to.
SERVICE_NOT_ACTIVE409The service exists but is not live.

Request problems

CodeHTTPWhat it means
VALIDATION_FAILED422A field is missing or malformed. Also refused here: a serviceId that is not a number, which is checked before your grant is looked up.
INVALID_MSISDN422The number is not a valid subscriber number.
DUPLICATE_TRANSACTION_ID409This spTransactionId has been used for a different request. Generate a new one per attempt.

PIN and OTP

CodeHTTPWhat it means
PIN_NOT_REQUESTED422You are verifying a code that was never issued for this number and service.
PIN_INVALID422Wrong code.
PIN_EXPIRED422The code was correct once but has timed out. Issue a new one.
PIN_ATTEMPTS_EXCEEDED422Too many wrong attempts. Issue a new code.

Subscriber state

CodeHTTPWhat it means
ALREADY_SUBSCRIBED409Already has a live subscription to this service.
NOT_SUBSCRIBED409The operation needs a live subscription and there is none.
SUBSCRIBER_BLACKLISTED403This number may not be subscribed or messaged. Do not retry on any channel.

Limits

CodeHTTPWhat it means
CONTENT_LIMIT_EXCEEDED429The subscriber's daily content budget for this service is spent.
PURCHASE_DAILY_LIMIT_REACHED429The subscriber's purchase count limit for today is reached.
PURCHASE_AMOUNT_LIMIT_REACHED429The subscriber's purchase value limit is reached.
SHORT_CODE_PART_LIMIT_REACHED429The short code's own send budget is spent.

These are ceilings on the subscriber or the short code, not on you: they reset, and the reset is not something your retry can hurry.

Content and messaging

CodeHTTPWhat it means
CONTENT_TOO_LONG422Longer than this service permits. Messages are not split: see Send SMS.
CONTENT_NOT_ALLOWED_TODAY403This service does not deliver content on this day of the week.

Charging

CodeHTTPWhat it means
CHARGE_FAILED402The operator refused the charge.
INSUFFICIENT_BALANCE402The subscriber cannot pay right now.
PARENT_SUBSCRIPTION_REQUIRED409This purchase needs an active subscription to its parent service.
PURCHASE_CHANNEL_NOT_ENABLED403One-time purchase is not enabled for this service.

Anti-fraud

CodeHTTPWhat it means
FRAUD_BLOCKED403The check ran and returned a negative verdict. Do not retry.
FRAUD_CHECK_UNAVAILABLE503The check could not run. Retryable, and nothing was consumed.
FRAUD_TRANSACTION_UNKNOWN422We have no record of this transaction identifier. Your page did not fetch the anti-fraud script with this ti, or used a different one. This is not a decline: it exists as its own code so that it cannot be mistaken for one. See Anti-fraud.
ANTIFRAUD_SCRIPT_UNAVAILABLE503We could not fetch the script for your page. Retryable.

Server

CodeHTTPWhat it means
INTERNAL_ERROR500Our fault. Retry with backoff, and quote the requestId if it persists.