G-SMS.

Documentation

Error codes

The API returns one error shape everywhere, with a stable code and a human-readable message. Thirty-nine codes exist. They are all listed below, with what to do about each one.

The shape of an error

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "code": "TEXT_TOO_LONG",
  "message": "Le texte dépasse 1600 caractères"
}
  • Branch on code, never on message. The code is part of the contract; the message is prose for a human reader, it is written in French today, and it can change at any time.
  • If you surface errors to your own users, map the code to a sentence of your own, in their language. That is exactly what this console does.
  • The HTTP status tells you the family; the code tells you the cause. Both are stable.
One response breaks this shape, and it is deliberate: a duplicate clientReference on POST /v1/sms returns 409 with the existing message, not with an error object. Handle it as a success. Idempotency explains why.

HTTP statuses at a glance

StatusMeaningRetry?
400The request is wrong.No — fix the request first.
401No usable API key.No.
402Not enough credit.After a top-up.
403The account is not allowed to send.No.
404Unknown, or not yours.No.
409Conflict. On a send, this is the duplicate reference case.No — and on a send, nothing failed.
429Too fast, or daily quota reached.Yes, after Retry-After.
500Our fault.Yes, with exponential backoff.
503A dependency is switched off or unreachable.Yes, after Retry-After.

Retry-After is sent as a number of seconds on 429 RATE_LIMITED (1 s) and on 503 OPERATOR_DISABLED (3600 s). When the header is absent, use your own backoff.

Sending an SMS

The codes a /v1 integration actually meets. Everything else below comes from the console.

CodeStatusMeaningWhat to do
INVALID_API_KEY401The key is missing, malformed, unknown or revoked.Send the header as "Authorization: Bearer gsk_…". If the key was revoked, create a new one in the console.
ACCOUNT_SUSPENDED403The account behind the key is no longer active.Contact support. Retrying will not help.
TEXT_EMPTY400The text is missing, empty or only whitespace.Check the variable you interpolate into the message before sending.
TEXT_TOO_LONG400The text is longer than 1600 characters.Shorten the message, or split it yourself into several sends.
INVALID_NUMBER400The number is not a Cameroonian mobile number.Accepted formats: +2376XXXXXXXX, 2376XXXXXXXX, 6XXXXXXXX. Validate at input time, not at send time.
PRICE_NOT_CONFIGURED400No price is set for the operator this number resolves to.Nothing you can fix from the client side: report it, it is a configuration gap.
OPERATOR_DISABLED503Sending to that network is temporarily switched off. Nothing was charged.Honour the Retry-After header (3600 seconds) and queue the message on your side.
QUOTA_EXCEEDED429The daily quota of the account is reached.Retry after midnight UTC, or ask for a higher quota. Disabled by default.
RATE_LIMITED429More than ten requests per second on this key.Honour Retry-After (1 second) and space out your loop.
INSUFFICIENT_BALANCE402The balance does not cover the price of this message. Nothing was queued.Top up in the console. Watch balanceAfterXaf on each send to top up before you run dry.
NOT_FOUND404Unknown identifier — or a message that belongs to another application.Check the messageId and the key you used. The API never answers 403 here, on purpose.
BAD_REQUEST400Malformed JSON, or a parameter of the wrong type.Check the Content-Type header and the body you actually sent, not the one you meant to send.
VALIDATION_ERROR400A field failed validation; the message names the field.Read the message field: it is the only place the offending field appears.
INTERNAL_ERROR500Unexpected failure on our side.Retry with exponential backoff. If it persists, report it with the time of the call.

Account and sign-in

Returned while creating an account, verifying a number or signing in.

CodeStatusMeaningWhat to do
ACCOUNT_PENDING403The phone number of the account has not been verified yet.Enter the code received by SMS to activate the account.
ACCOUNT_ALREADY_ACTIVE400The account is already verified.Sign in instead of asking for another verification code.
INVALID_CREDENTIALS401Wrong email or password.Reset the password from the sign-in screen.
INVALID_EMAIL400The email address is missing or malformed.Provide a valid address.
PASSWORD_TOO_SHORT400The password is shorter than 8 characters.Use at least 8 characters.
EMAIL_TAKEN409An account already exists with this email address.Sign in, or recover the password.
PHONE_TAKEN409An account already exists with this phone number.Sign in with that account, or use another number.
OTP_INVALID400The verification code does not match.Check the digits, or request a new code.
OTP_EXPIRED400The verification code is past its validity window.Request a new code.
OTP_MAX_ATTEMPTS400Too many wrong attempts on the same code.Request a new code; the old one is burned.

Applications, webhooks and credit

Returned by console operations on applications, webhook endpoints and top-ups.

CodeStatusMeaningWhat to do
INVALID_SLUG400Application slug outside the allowed shape.Lowercase letters, digits and hyphens, 2 to 50 characters.
SLUG_TAKEN409Another application already uses this slug.Pick a different one. The slug is what webhooks carry in applicationId.
INVALID_URL400The webhook URL does not start with http:// or https://.Give an absolute URL. Use https:// — the payload carries phone numbers.
UNSUPPORTED_EVENT400The subscription asks for an event type that does not exist.Only sms.sent exists today; it fires on every status change.
INVALID_AMOUNT400Top-up amount below the minimum, or not a positive number.Check the minimum shown on the top-up screen.
TOPUP_PENDING409A top-up is already in progress on this account.Finish or wait for the current one before starting another.
TOPUP_DISABLED503Online top-up is switched off.Ask for a manual credit while it is unavailable.
CAMPAY_UNAVAILABLE503The mobile money provider did not answer.Try again in a few minutes. No money was taken.

Administration

Routing rules, prices and statistics filters, reserved for administrators.

CodeStatusMeaningWhat to do
INVALID_OPERATOR400Unknown operator in a routing rule.Use ORANGE, MTN, CAMTEL, NEXTTEL or DEFAULT.
INVALID_PREFIX400Malformed prefix in a routing rule.Digits only, starting with 6.
DUPLICATE_PREFIX400The same prefix appears twice in the submitted list.Remove the duplicate line.
DUPLICATE_OPERATOR400The same operator appears twice in the submitted list.Remove the duplicate line.
INVALID_PRICE400A negative price was submitted.Prices are whole XAF, zero or more.
INVALID_STATUS400Unknown status in a filter or an account update.Use one of the documented values.
INVALID_PERIOD400The start of the period is not before its end.Swap from and until, or widen the window.

Writing a client that survives

  • Retry only 429, 500 and 503 — and only with backoff. Retrying a 400 in a loop simply sends the same wrong request faster.
  • Always send a clientReference. It is what makes a retry safe when you cannot tell whether the first call went through.
  • Log the code, the HTTP status and your own reference. Those three are enough to reconstruct any incident.
  • Handle 402 before it happens: read balanceAfterXaf on every send, or poll GET /v1/balance, and alert yourself early.

Ready to send your first SMS?

Create an account, get 100 FCFA of credit and an API key straight away.

Create account