Error Handling
Handle Whatsable API v1 errors: read the error body, decide whether to retry, and retry safely with Idempotency-Key.
Every Whatsable API v1 error has the same body, and every code is listed with its fix on API v1 errors. This page shows how to act on an error in your code.
Read the error body
A 4xx or 5xx response looks like this:
{
"error": {
"type": "permission",
"code": "insufficient_scope",
"title": "...",
"message": "...",
"how_to_fix": "...",
"owner": "caller",
"retryable": false,
"docs_url": "https://docs.whatsable.app/api/errors#insufficient_scope",
"request_id": "..."
}
}- Branch on
code. It is stable. Thetitle,messageandhow_to_fixare for people, and their wording can change. retryablesays whether the same request can succeed later without a change.ownersays who must act:caller(you change the request or the account),whatsable, ormeta.request_ididentifies the request. Give it to support when you ask about one.
The API v1 overview explains every field.
A send can fail with 201
A send that Whatsable recorded answers 201 Created, even when WhatsApp refused the message. Always read status in the body:
status: "sent": WhatsApp accepted the message.status: "failed": readerror. It has the samecode,retryableandhow_to_fixfields as an error response.
When to retry
| What you got | What to do |
|---|---|
429 rate_limited | Wait the seconds in the Retry-After header, then retry. See rate limits. |
An error with retryable: true | Retry later, with a growing delay between attempts. |
An error with retryable: false | Do not retry. Fix the cause that how_to_fix names, or show it to the person who can. |
201 with status: "failed" and retryable: true | Send again later with a new Idempotency-Key. |
201 with status: "failed" and retryable: false | Do not send it again. |
Retry safely with Idempotency-Key
Send an Idempotency-Key header on every POST that creates something, such as a send. Use a new key for each new message, and the same key for each retry of it. The API remembers a key for 24 hours.
- A
4xxor a503is not stored. Fix the request if needed and retry with the same key. The retry runs. - A
2xxor a500is stored, because the message may already have gone out. A retry with the same key returns the stored answer and never sends twice. - The same key with a different body gets
409 idempotency_key_reused.
Example
async function sendTemplate(apiKey, idempotencyKey) {
const response = await fetch('https://api.whatsable.app/v1/messages', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({
to: '+15551234567',
type: 'template',
template: { name: 'order_update', language: 'en', variables: { 1: 'Ana', 2: '#1042' } },
}),
});
const body = await response.json();
if (!response.ok) {
const { code, retryable, how_to_fix } = body.error;
if (response.status === 429) {
const waitSeconds = Number(response.headers.get('Retry-After') ?? 1);
return { retryAfterSeconds: waitSeconds };
}
return { failed: code, retryable, howToFix: how_to_fix };
}
if (body.status === 'failed') {
return { failed: body.error.code, retryable: body.error.retryable, howToFix: body.error.how_to_fix };
}
return { messageId: body.id };
}The template's variable names come from Read a template. The full request is on Send a message.