Skip to main content

Errors

Every error has a code that never changes. Branch on error.code, show error.message, and look the code up here.

The error body​

A failed request answers with an HTTP status and an error object.

{
"error": {
"type": "billing_error",
"code": "E03001",
"name": "InsufficientBalance",
"message": "Insufficient account balance. Top up to continue sending.",
"doc_url": "https://docs.ponitor.com/api/errors#E03001",
"request_id": "2d017493-d307-4628-b9a3-068160069183"
},
"message": "Insufficient account balance. Top up to continue sending."
}
FieldAlways thereWhat it is
typeYesThe kind of error, from the list below, for branching broadly.
codeYesE and five digits. It never changes and is never reused. Branch on this.
nameYesA readable name for the code, such as InsufficientBalance, for your logs.
messageYesWhat happened, to show or log. Don't parse it: the words can change.
doc_urlYesThe code's entry on this page.
request_idYesThe request's id, also sent as the X-Request-Id header. Quote it when you contact support.
paramNoThe one field at fault, when only one is.
detailsNoOn a validation error, every field at fault, each with its param and message.

A request that fails validation lists each field in details. param is a dotted path: recipients.0 is the first recipient.

{
"error": {
"type": "validation_error",
"code": "E01001",
"name": "ValidationError",
"message": "The request has 2 problems.",
"doc_url": "https://docs.ponitor.com/api/errors#E01001",
"request_id": "c1f0b7a2-5e1d-4c8e-9a0b-7d6e5f4c3b2a",
"details": [
{ "param": "externalId", "message": "externalId is required" },
{ "param": "content", "message": "content must be 2 or more characters long" }
]
},
"message": "The request has 2 problems.",
"errors": [{ "message": "externalId is required" }, { "message": "content must be 2 or more characters long" }]
}

Fields from before codes​

message beside error, and on some errors code (such as RECIPIENT_OPTED_OUT) and errors, are what errors carried before codes. They are deprecated and still sent, so code written against them keeps working. Use error.message, error.code and error.details in new code.

Types and statuses​

typeStatusMeaningRetry?
validation_error400A field is missing or invalid. See details.No. Fix the request first.
bad_request_error400The request can't be done as sent: a sender that isn't yours, a number that isn't one, a body that isn't JSON.No
billing_error400The balance or the workspace's credit is too low, or prices aren't set up.No. Add funds first, or contact support if prices aren't set up.
auth_error401The API key is missing, wrong or revoked, or sent to the other base URL.No. Fix the key or the base URL.
permission_error403Your team hasn't completed compliance or is suspended, or the workspace is paused or wasn't given that product or sender.No
not_found_error404Your team has nothing with that id, or there's no endpoint at that path.No
conflict_error409The request clashes with the state things are in: a price that changed, a request still being processed, or something the sandbox doesn't do.Only E01008
payload_too_large_error413The body is too large.No
unprocessable_error422The request is valid but can't be done, such as a marketing template to someone who unsubscribed.No
rate_limit_error429Too many requests in a minute. See Rate limits.Yes, after a pause.
internal_error500Something failed on our side.Yes, with the same externalId.
service_unavailable_error503A service Ponitor relies on didn't answer. Nothing was done.Yes, shortly.

A request that ends in a 4xx isn't charged. A retry after a 5xx or a timeout with the same externalId doesn't send or charge twice. See Retries and externalId.

Why a message wasn't delivered​

A message that ends as EXPIRED, UNDELIVERED or FAILED has a failureCode (an E11 code), and a failedReason in plain words that you can show your users. They come with the message: in its webhook, and from Get a message.

{
"message": {
"id": "e2c38865-dc0a-4299-baef-c07a9bfa9c33",
"status": "EXPIRED",
"failureCode": "E11001",
"failedReason": "Recipient unreachable: phone was off or out of coverage until the message expired"
}
}

Branch on failureCode, not on failedReason. A message that failed before codes existed may have no failureCode.

Handling errors​

This example retries what's safe to retry and logs the rest.

const response = await fetch('https://api.ponitor.com/messaging/v1/messages', {
method: 'POST',
headers: { apiKey: process.env.PONITOR_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});

if (response.ok) {
const { message } = await response.json();
// 201: new message. 200: the original, for an externalId you'd already used.
} else {
const { error } = await response.json().catch(() => ({ error: undefined }));

if (response.status === 429 || response.status >= 500 || error?.code === 'E01008') {
// Wait, then send the same request again, with the same externalId.
} else if (error?.code === 'E03001') {
// Out of balance: top up, then send again.
} else {
// Fix the request or the key; sending it unchanged fails again.
console.error(response.status, error?.code, error?.message, error?.details, error?.request_id);
}
}

Every code​

Each code links here from its doc_url. Codes are never renamed or reused; new ones may be added, so treat a code you don't know by its type.

Requests​

The request itself: its body, its path, its rate.

CodeNameStatusMeaningWhat to doRetry?
E01000InternalError500Something failed on our side. Nothing you sent caused it.Send the same request again, with the same externalId so nothing is sent twice. If it keeps happening, contact support with the request_id.Yes
E01001ValidationError400The body was read, but one or more fields are missing or invalid. details lists each one.Fix each field in details, then send the request again.No
E01002BadRequest400The request can't be done as sent. The message says why.Change the request as the message says, then send it again.No
E01003MalformedJson400The body couldn't be read as JSON.Send a JSON body, with the header Content-Type: application/json.No
E01004PayloadTooLarge413The body is over the size the endpoint takes.Send a smaller body. Upload a file and send its link instead of the file.No
E01005NotFound404Your team has nothing with that id.Check the id, and that you use the key of the team that owns it.No
E01006RouteNotFound404The path or the method is not one the API has.Check the path and the method against the API reference.No
E01007Conflict409The request clashes with something that already exists or has changed.Read the object again, then decide what to send.No
E01008RequestInProgress409A request with the same externalId is still being handled.Wait a moment, then send the same request again. You get the original back.Yes
E01009NotInSandbox409The sandbox does without it: payments, Sender ID requests, and teams and keys, which are managed in Ponitor.Do it in Ponitor, with a live key.No
E01010Unprocessable422Every field is right, but what it asks for is not possible now.The message says why. Change what you ask for.No
E01011RateLimited429Your team sent more requests in a minute than its limit. Before codes: rate_limited.Wait for the seconds in the Retry-After header, then send again. See Rate limits.Yes
E01012ServiceUnavailable503Something Ponitor relies on is down for a moment. Nothing was sent or charged. Before codes: unavailable.Send the same request again shortly.Yes

Sign-in and access​

The API key, the team, its compliance, and what a workspace may use.

CodeNameStatusMeaningWhat to doRetry?
E02001Unauthenticated401The request has no API key or sign-in, or one Ponitor no longer accepts.Send your API key in the apiKey header.No
E02002InvalidApiKey401The key is not one of your team's live keys.Check that you copied the whole key. A key is shown only once: if you've lost it, generate a new one under Settings › Developers › API Keys.No
E02003KeyForOtherEnvironment401A sandbox key was sent to api.ponitor.com, or a live key to sandbox-api.ponitor.com.Send sandbox keys to sandbox-api.ponitor.com and live keys to api.ponitor.com.No
E02004ApiKeyAtAppAddress401An API key was sent to the address the app uses.Send the request to api.ponitor.com (live) or sandbox-api.ponitor.com (sandbox).No
E02005SessionExpired401The sign-in has expired or is not valid.Sign in again.No
E02006TeamNotFound401The team the key or the sign-in belongs to no longer exists.Use a key of a team that exists, or contact support.No
E02007PermissionDenied403You are signed in, but this action is not one you may take.Ask an owner of the team for access.No
E02008RoleNotAllowed403Your role in the team does not include this permission.Ask an owner to give you a role that has it.No
E02009NotATeamMember403The request names a team you are not in.Switch to a team you belong to, or ask its owner for an invitation.No
E02010TeamNotVerified403Live sending needs a verified team. The team's compliance is pending, has expired or was never sent.Finish compliance in Settings › Compliance. Until then, use the sandbox.No
E02011TeamSuspended403Ponitor suspended the team, so it can't send.Contact support.No
E02012WorkspacePaused403An owner paused the workspace, so it can't send.Ask an owner of the team to resume it.No
E02013WorkspaceArchived403The workspace was archived and does nothing more.Use another workspace.No
E02014ProductNotGiven403The team did not give the workspace SMS, WhatsApp, airtime or USSD.Ask an owner of the team to give it to the workspace.No
E02015SenderNotGiven403The sender belongs to the team, but the workspace may not use it.Ask an owner of the team to give the sender to the workspace, or use another sender.No
E02016StaffOnly403Only Ponitor's staff may do this.Contact support.No

Billing​

The balance, a workspace's credit, and prices.

CodeNameStatusMeaningWhat to doRetry?
E03001InsufficientBalance400The team's balance can't cover the charge. Nothing was sent or charged.Add funds under Billing, then send again.No
E03002InsufficientWorkspaceCredit400The workspace's credit can't cover the charge. Nothing was sent or charged.Ask an owner of the team to give the workspace more credit.No
E03003PricingNotSet400The team has no price for this channel yet.Contact support.No
E03004PriceChanged409The price is not the expectedPrice you sent. Nothing was charged or sent. Before codes: PRICE_CHANGED.Read the price again, then send it as expectedPrice.No

Sending messages​

A message refused when you send it. Nothing is sent or charged.

CodeNameStatusMeaningWhat to doRetry?
E10001SenderNotFound400The sender is not one of your team's approved senders for this channel.Use an approved sender from SMS › Sender IDs, SMS › Short Codes or WhatsApp › Accounts in the app.No
E10002InvalidRecipient400The recipient is not a phone number Ponitor can send to.Send the number in international format, such as +231770123456.No
E10003NoValidRecipients400None of the numbers, contacts or lists has a number Ponitor can send to.Check the numbers, then send again.No
E10004CountryNotOffered400SMS to this country is not offered.See Prices for the countries Ponitor sends to, or contact support to ask for one.No
E10005TemplateNotFound400The template id is not an approved template of the sending number.Use the Template ID from WhatsApp › Templates in the app.No
E10006OutsideServiceWindow400The customer hasn't written in the last 24 hours, so WhatsApp takes only a template.Send an approved template instead.No
E10007WhatsAppNotConnected409The WhatsApp Business Account was removed, or the access Ponitor had to it was taken back. Before codes: WHATSAPP_NOT_CONNECTED.Connect the account again under WhatsApp › Accounts.No
E10008RecipientOptedOut422The person unsubscribed from your WhatsApp marketing. Before codes: RECIPIENT_OPTED_OUT.Don't send them marketing. Utility and authentication templates, and replies, still go.No

Delivery​

Why a message didn't arrive. These come on the message, as failureCode, in its webhook and from Get a message, never as an error answer.

CodeNamefailedReasonMeaningWhat to doSend again?
E11001RecipientUnreachableRecipient unreachable: phone was off or out of coverage until the message expiredThe phone was off, or out of coverage, for as long as the network kept trying.Send it again later, when the phone is likely on.Yes
E11002NumberNotInServiceThe number may no longer existThe network says the number is not in service.Check the number with the person, and stop sending to it if it's wrong.No
E11003InvalidNumberInvalid recipient numberThe network refused the number as not valid.Check the number, and send it in international format.No
E11004CannotReceiveSmsA landline, or a network that can't receive itThe number can't receive SMS: a landline, or a network that takes none.Use a mobile number.No
E11005FilteredByNetworkFiltered by the networkThe network's filter held the message back, usually for its content or its sender.Use a registered Sender ID, and avoid links or words that read as spam.No
E11006SenderIdRejectedSender ID not accepted by the networkThe network doesn't accept this Sender ID.Use another Sender ID, or ask support to register this one with the network.No
E11007NetworkBusyNetwork busy, message not acceptedThe network was too busy to take the message. It was not charged.Send it again in a few minutes.Yes
E11008NetworkUnreachableThe network could not be reachedPonitor couldn't reach the network, so nothing was sent or charged.Send it again in a few minutes.Yes
E11009NotConfirmedThe network did not confirm the messageThe network never answered, so the message may or may not have gone out. It was not charged.Check with the person before you send it again.No
E11010NetworkRefusedThe network did not accept this messageThe network refused the message without a reason Ponitor can name. It was not charged.Check the number and the sender. If both are right and it keeps happening, contact support.No
E11011UndeliverableThe carrier could not deliver this messageThe network accepted the message but could not deliver it, for example to a barred number.Check the number with the person.No
E11012RejectedByNetworkThe carrier rejected this messageThe network accepted the message, then refused to deliver it.Check the number and the content. Contact support if it keeps happening.No
E11013CancelledByNetworkThe carrier cancelled this messageThe network cancelled the message before delivering it.Send it again.Yes
E11014CountryNotSupportedPonitor doesn't send SMS to this country yetSMS to the number's country is not switched on. It was not charged.Contact support to ask for the country.No
E11015NotSentThe message could not be sentPonitor couldn't send the message. It was not charged.Send it again. Contact support if it keeps happening.Yes
E11016NoReasonGivenThe network gave no reasonThe network reported the message as not delivered, without saying why.Send it again later. Contact support if it keeps happening.Yes
E11017NumberBarredThe number is barred from receiving messagesThe network bars the number from receiving messages, for example for an unpaid bill or at its owner's request.Check the number with the person. Messages will fail until the network lifts the bar.No
E11099NotDeliveredIt wasn't delivered.The message wasn't delivered, for a reason that isn't one of the codes above.Contact support with the message id.No
E11101NotOnWhatsAppNot a WhatsApp numberThe number has no WhatsApp account.Send an SMS instead.No
E11102ContentRejectedWhatsApp didn't accept the contentWhatsApp refused the message's content or its format.Check the content against WhatsApp's rules, then send it again.No
E11103OutsideReplyWindowOutside the 24-hour reply windowThe customer hadn't written in the last 24 hours, so only a template could go.Send an approved template instead.No
E11104SentTooFastSent faster than WhatsApp allowsThe number sent more than WhatsApp allows in a short time.Send it again in a few minutes, and spread large sends out.Yes
E11105MediaUnavailableA file couldn't be downloadedWhatsApp couldn't download the image, video, audio or document from its link.Check that the link is public and works, then send it again.No
E11106WhatsAppRefusedNumberNot on WhatsApp, or WhatsApp refused the numberThe number isn't on WhatsApp, or WhatsApp won't deliver to it.Send an SMS instead.No
E11107TemplateLanguageMissingThe template isn't in that languageThe template has no approved version in the language asked for.Send it in a language the template has, or add that language in WhatsApp › Templates.No
E11108NumberPausedByWhatsAppWhatsApp won't send to this number for nowWhatsApp is holding messages to this number back for a while.Send it again later.Yes
E11109MarketingHeldBackWhatsApp held back this marketing messageWhatsApp limits how many marketing messages one person gets, and held this one back.Send fewer marketing messages to the same people.No
E11110WhatsAppAccountLockedYour WhatsApp number or account is lockedWhatsApp locked your number or your WhatsApp Business Account.Check the account in WhatsApp Manager, then contact support.No
E11111WhatsAppAccountDisabledYour WhatsApp Business Account is disabledWhatsApp disabled your WhatsApp Business Account.Check the account in WhatsApp Manager, then contact support.No

Airtime​

A top-up or data bundle refused when you buy it.

CodeNameStatusMeaningWhat to doRetry?
E12001ProductUnavailable400The product is not one Ponitor sells now.List the products again, and use one of them.No
E12002ProductForOtherNetwork400The product is sold for numbers on another network than the recipient's.Use a product for the recipient's network.No
E12003UnsupportedNetwork400Airtime goes only to Orange and Lonestar Cell MTN numbers in Liberia.Use an Orange or MTN number.No
E12004InvalidMsisdn400The msisdn is not a phone number.Send the number in international format, such as 231770123456.No
E12005TooManyRecipients400One batch can pay only so many recipients.Split the recipients into smaller batches.No