On this page6 sections
A WhatsApp message fails in one of two places. Either the Cloud API rejects your request and returns an error code with no message ID, or it accepts the request and a status webhook later reports failed with an errors array. Find which one you have, group the code by cause, and you know whether to fix, wait or stop.
This is a runbook for the morning a send job shows failures, not a code dictionary. For what each field in an error object means, see the API error codes glossary entry.
First question: did the request fail, or did the message?
Meta's error codes reference says Cloud API errors arrive "either synchronously as a Graph API response" or asynchronously through a webhook. The two need different handling.
- The request failed. Your call returned an HTTP error with an error object:
code,message,error_data.detailsand anfbtrace_id. No message ID was created, so no status webhook will ever follow. The fix is almost always in your request, token or account. - The message failed. Your call returned success with a message ID (
wamid), and a status webhook later arrived withstatus: "failed". Meta's messages documentation is explicit that the success response confirms acceptance, not delivery.
The failed status has this shape in Meta's status webhook reference (trimmed, illustrative):
{
"statuses": [
{
"id": "wamid.HBgL...",
"status": "failed",
"timestamp": "1792473600",
"recipient_id": "91XXXXXXXXXX",
"errors": [
{
"code": 131026,
"title": "<ERROR_TITLE>",
"message": "<ERROR_MESSAGE>",
"error_data": { "details": "<ERROR_DETAILS>" },
"href": "https://developers.facebook.com/documentation/business-messaging/whatsapp/support/error-codes"
}
]
}
]
}
Match the webhook back to your send by id, which is the same wamid the API returned. The errors array is only present on failures.
Group the code by cause
Most codes fall into one of seven causes. The cause tells you who fixes it and whether time alone helps.
| Cause | Codes | What it means | What to do |
|---|---|---|---|
| Access | 0, 190, 10, 200–299, 131005 | Token expired or invalid, or a permission is missing | Issue a new token or restore the permission; nothing sends until then |
| Payload | 100, 131008, 131009, 132000, 132001, 132012, 132018 | A parameter is missing, invalid, or does not match the approved template | Fix the request; resending it unchanged fails the same way |
| Rate | 4, 80007, 130429, 131056 | App, account, throughput or pair rate limit reached | Back off and retry |
| Window | 131047 | More than 24 hours since the user last replied | Send an approved template instead |
| Recipient | 131026, 130403 | Not reachable on WhatsApp, or your business has blocked the user | Do not retry; fix the contact data, or unblock the user if the block was a mistake |
| Marketing limits | 131049, 131050, 131064 | Held back for ecosystem engagement, user opted out of marketing, or limits from template classification violations | Wait, suppress, or fix template categories |
| Account and template | 131042, 368, 130497, 131048, 132015, 132016, 133010 | Billing problem, policy restriction, country restriction, spam restriction, paused or disabled template, unregistered number | Fix in WhatsApp Manager or with your provider |
A few of these deserve a sentence more:
- 132001 after a template edit. The template name exists but not in the language you sent, or it is not approved yet. Check the exact name and locale code.
- 131026 is the catch-all for an unreachable user: not a WhatsApp number, terms not accepted, or an outdated app. The error 131026 entry covers the data-quality side.
- 131042 points at the WhatsApp Business Account's billing setup, not at your code.
- 132015 and 132016 mean the template was paused for low quality, or paused so often it is now disabled. A disabled template has to be replaced with a new one.
Temporary platform errors (2, 131016, 133004) sit outside these groups, and Meta's guidance is to check the WhatsApp Business Platform status page before trying again. Code 1 can be either an outage or a malformed request, so check both, and 131000 is an unknown error to retry and, if it persists, take to support.
Retry rules that do not make things worse
A retry is only useful when the cause is time. Everywhere else it turns one failure into many.
Retry with backoff:
- 130429: throughput. Meta's throughput documentation puts the default at up to 80 messages per second per number, with automatic upgrades to up to 1,000 for eligible numbers. Slow the sender rather than hammering it.
- 131056: pair rate limit. Meta's platform overview allows 1 message every 6 seconds to the same user, with bursts of up to 45 deducted from future quota, and suggests retrying after 4^X seconds, increasing X after each failure.
- 4 and 80007: app and account call limits. Reduce request volume, then retry.
- 2, 131016, 133004 and 131000: temporary or unknown platform errors.
Wait, then decide:
- 131049: Meta's reference says to wait at least 24 hours, and that resending sooner returns the same error.
Never retry automatically:
- 130403: your business has blocked this user. Unblock them first if the block was a mistake.
- 131050: the user stopped receiving marketing messages from you. Suppress the contact for marketing.
- 131026: repeated sends to an unreachable number change nothing.
- Every access, payload and account code: the next attempt fails identically until a person fixes the cause.
What to log for every failure
When a failure reaches a person, the log decides whether diagnosis takes five minutes or a day. For each failure, store:
- the
wamid(for webhook failures) or the full error object (for request failures); code,titleanderror_data.details, which often names the actual cause in plain language;fbtrace_idfrom synchronous errors, which Meta's support team uses to trace the request;- the phone number ID, template name and language code you sent;
- the recipient as a masked or hashed value, not the raw number, so the log does not become a personal data store of its own;
- the time in IST alongside the Unix timestamp from the webhook.
Keep the raw error alongside your parsed fields. Meta's reference notes that error_subcode is deprecated and not returned from v16.0, so code that branched on it silently stopped working; the raw body shows you what actually arrived.
A triage order for a bad morning
Take a hypothetical coaching institute in Jaipur that sends 3,000 fee reminders at 9:00 IST and sees 400 failures by 9:30. Work through it in this order:
- Count failures by code. One dominant code is a single cause; a spread across many codes points at per-recipient problems.
- Check request-level failures first. If the job logged access or payload errors, nothing after that point sent. Fix and re-run only the rejected batch.
- Read
error_data.detailsfor the top code. For 132000 or 132012 it usually names the parameter that does not match the template. - Separate cures from stops. Queue rate-limited messages for a backed-off retry; mark 131026 and 130403 contacts so the next run skips them.
- Escalate with evidence. If 131000 or an account code persists, raise it with the
fbtrace_id,wamidand time.
The webhooks guide covers receiving statuses reliably, which every step above depends on.
How InfiQ helps with failed messages
InfiQ's message status tracking shows sent, delivered, read and failed statuses per message and per campaign. If you build on the API, InfiQ's webhooks push delivery, read and failed status events to your own endpoint, so the triage above can run in your systems.

