Reference
API errors
Every failure returns the same three fields. Branch on error
— it is a stable string, and it will not be renamed under an integration
that was correct when it was written.
{
"error": "insufficient_credit",
"message": "Not enough credit to accept this request…",
"docs_url": "/docs/errors#insufficient_credit"
}
25 codes. The HTTP status is worth reading alongside the code:
a 4xx is about your request, a 5xx is about us.
Credentials
The key itself — missing, wrong, retired, or not allowed to do this.
unauthorized
HTTP 401
retrying will not help
#
No API key was supplied. Send it as `Authorization: Bearer <key>` or `X-Api-Key: <key>`.
What to do
Send the key on every request. `Authorization: Bearer <key>` is the usual form; `X-Api-Key: <key>` is accepted identically.
key_invalid
HTTP 401
retrying will not help
#
That API key is not valid.
What to do
Check for a truncated paste. A key is one unbroken string, and a copied line break is the common cause.
key_revoked
HTTP 401
retrying will not help
#
That API key has been revoked. Issue a new one from your dashboard.
What to do
Issue a replacement at /app/keys. Revocation takes effect on the next call, so there is no window to wait out.
key_expired
HTTP 401
retrying will not help
#
That API key has expired. Issue a new one from your dashboard.
What to do
Issue a replacement at /app/keys, and set a longer expiry or none at all if this was not deliberate.
scope_denied
HTTP 403
retrying will not help
#
This API key does not carry the scope required for this endpoint.
What to do
Add the scope the endpoint needs, or use a key that already carries it. Sending needs `send`, reading messages needs `read`, balance and usage need `balance`.
ip_not_allowed
HTTP 403
retrying will not help
#
This API key is restricted to an IP allowlist that does not include this address.
What to do
Add the calling address to the key's allowlist, or clear the allowlist. Check your egress address rather than your office one — a NAT or proxy changes it.
tenant_suspended
HTTP 403
retrying will not help
#
This account is suspended. Contact support to restore service.
What to do
Contact support. Nothing will be accepted until the account is restored, so stop retrying.
The recipient
Refused at the boundary and never charged. On a multi-recipient send these appear per recipient inside a 200 instead.
invalid_number
HTTP 400
retrying will not help
#
That is not a phone number.
What to do
Check the value reached us as you meant it. Any format is accepted, so this usually means letters, an empty string, or a truncated field.
unroutable_number
HTTP 400
retrying will not help
#
This gateway carries Bhutanese numbers only (+975), on a prefix an operator claims.
What to do
Use a Bhutanese number on a prefix an operator claims: 16 and 17 are B-Mobile, 77 is TashiCell. A foreign number is a real number we do not carry.
The message
The text or its options ask for more than the plan carries. Nothing is ever truncated to fit.
message_too_long
HTTP 400
retrying will not help
#
This message needs more segments than your plan permits. Shorten it or upgrade — it was not truncated and not charged.
What to do
Shorten the body, or upgrade for a higher segment ceiling. POST /api/v1/validate returns the exact count for free before you commit.
unicode_not_allowed
HTTP 400
retrying will not help
#
This message needs UCS-2 (it contains a character outside the GSM alphabet), which your plan does not include.
What to do
Replace the non-GSM characters, or upgrade. A curly apostrophe pasted from a word processor is the usual single culprit.
too_many_recipients
HTTP 400
retrying will not help
#
More recipients than your plan permits in one request. Split it into smaller batches.
What to do
Split the request into smaller batches. The ceiling is per REQUEST, not per second, so several batches back to back are fine.
scheduling_not_allowed
HTTP 400
retrying will not help
#
Scheduled sending is not included in your plan.
What to do
Drop `scheduled_at` and send at the moment you want it, or upgrade to a plan that includes scheduling.
priority_not_allowed
HTTP 403
retrying will not help
#
Priority sending is not included in your plan. It moves a message ahead of ordinary traffic and is charged at a higher per-segment rate.
What to do
Drop `priority`, or upgrade. Priority overtakes ordinary traffic and bills at a higher per-segment rate.
The sender ID
Who the message appears to come from.
sender_invalid
HTTP 400
retrying will not help
#
That sender ID is not a valid format.
What to do
Use up to 11 GSM characters for an alphanumeric sender, or a plain number. Punctuation is the usual rejection.
sender_blocked
HTTP 400
retrying will not help
#
That sender ID is reserved and cannot be registered.
What to do
Choose a different sender ID. This one is reserved and no account can register it.
sender_not_allowed
HTTP 403
retrying will not help
#
Your plan sends under the platform sender ID and cannot set its own.
What to do
Omit `sender` and the platform sender ID is used, or upgrade to a plan that carries your own.
sender_not_approved
HTTP 403
retrying will not help
#
That sender ID is not approved for your account.
What to do
Register the sender ID at /app/senders and wait for approval. Approval is a human review, not an automatic step.
The request itself
The request was understood and still could not be carried out.
not_found
HTTP 404
retrying will not help
#
No such resource.
What to do
Check the id, and that it belongs to the account this key is on. One account cannot read another's messages, and that reads as absent rather than forbidden.
not_cancellable
HTTP 409
retrying will not help
#
This message has left the queue and can no longer be cancelled.
What to do
Nothing to do — it is with a carrier and cannot be recalled. Raise `hold_seconds` if you want a longer undo window next time.
validation_failed
HTTP 400
retrying will not help
#
The request body is missing a required field or has one of the wrong type.
What to do
Read `message` — it names the field. Every accepted field is listed under Send a message.
method_not_allowed
HTTP 405
retrying will not help
#
That HTTP method is not supported on this endpoint.
What to do
Use the method the endpoint documents. The response names the ones it allows.
Retrying
Only rate_limited and internal_error are worth
repeating. Every other code refuses the request as written, so an
identical retry gets an identical refusal — and a loop of them is how a
clear answer turns into a throttle. There is no Retry-After
header on this API; your plan's ceiling is on
/api/v1/pricing as max_tps,
and the limit is per second, so a short pause clears it.