How to read a WhatsApp Cloud API error before you look it up
The numeric code is the least useful part of a WhatsApp error response. The error_data.details field usually names the exact problem, and the first three digits of the code tell you which subsystem rejected you.
Last verified: August 2026 against the WhatsApp Cloud API. Meta revises error semantics periodically - check the official error reference for anything business-critical.
A full error response looks like this:
{
"error": {
"message": "(#131047) Re-engagement message",
"type": "OAuthException",
"code": 131047,
"error_data": {
"messaging_product": "whatsapp",
"details": "Message failed to send because more than 24 hours have passed since the customer last replied to this number."
},
"fbtrace_id": "A1bC2dE3fG4"
}
}Two habits will save you most of your debugging time. Log the whole error object, not just the code - the details string is written in plain English and is usually more specific than any reference table. And keep the fbtrace_id: it is the only thing Meta support can act on, and it is unrecoverable once discarded.
The code prefixes group roughly like this:
| Prefix | Subsystem | Typically means |
|---|---|---|
| 1xx (2-3 digits) | Graph API platform | Auth, permissions, malformed parameters |
| 130xxx | Throttling | Rate and volume limits |
| 131xxx | Messaging | Delivery, windows, recipients, policy |
| 132xxx | Templates | Parameters, formatting, approval state |
| 133xxx | Account registration | Number registration, two-step PIN |
If you only remember one thing: a 131xxx error is about this message to this person right now, while a 132xxx error is about the template itself and will fail identically for every recipient until you fix the template.
The 24-hour window: 131047 and why it is the error you will see most
131047 - Re-engagement message
Message failed to send because more than 24 hours have passed
since the customer last replied to this number.This is the most common WhatsApp API error in production, and it is not a bug. It is the platform's core rule working as designed.
WhatsApp permits free-form messages only inside a 24-hour window that opens when the customer messages you and closes 24 hours after their most recent message. Outside that window, the only thing you may send is a pre-approved template.
The nuance that trips people up: the window resets on every inbound message, not on the first one. A conversation that ran across three days with replies each day has a window that stayed continuously open. A conversation where the customer went quiet at 9am Monday closes at 9am Tuesday, even if your agent was still typing.
The fix is structural rather than technical:
- Track the timestamp of the last inbound message per contact, and check it before sending free-form.
- When the window is closed, send an approved template instead. The customer's reply to that template reopens the window.
- Do not attempt to "keep the window alive" with filler messages. Since 1 October 2026 service messages are billable, so that tactic now costs money for no benefit - see our guide to the October 2026 service message billing change.
The design implication
Any workflow that needs to reach a customer at an unpredictable later time - a delivery update, an appointment reminder, a support follow-up - must be built on templates from the start. Teams that build the happy path with free-form messages and discover 131047 in production usually face a rewrite, because template approval takes time and templates cannot carry arbitrary text.
Delivery failures: 131026, 131049, 131051 and the recipient problem
131026 - Message undeliverable
Deliberately vague, and it stays vague. Meta does not disclose the specific reason, for recipient privacy. The realistic causes, in rough order:
- The recipient has blocked your business
- The number is not registered on WhatsApp at all
- The recipient has not accepted WhatsApp's current terms
- The number is in a country where your account cannot message
- The number is formatted wrongly - see below, this is more common than it should be
Before assuming the recipient is at fault, check your formatting. WhatsApp requires the full international number without a leading +, without spaces, dashes or parentheses, and without a leading zero on the national portion. A UK mobile written as +44 07700 900123 must be sent as 447700900123. Keeping the zero is the single most frequent cause of a 131026 that has nothing to do with the recipient.
There is no API to test deliverability in advance. The send attempt is the test. Treat a 131026 as terminal for that contact: mark it undeliverable and stop retrying, because retries consume rate limit on a message that will never arrive.
131049 - Not delivered to maintain healthy ecosystem engagement
Meta is deliberately withholding delivery of a marketing message because the recipient receives too much marketing, or engages with too little of it. This is a per-recipient quality mechanism, not a rate limit, and it appears more often as your marketing volume grows.
The response is to send less marketing to less engaged contacts. Segment by engagement, suppress contacts who have not interacted in months, and move genuinely transactional content into utility templates where this rule does not apply.
131051 - Unsupported message type
You sent a message type the API does not accept, or a media type outside the permitted list. Check the media MIME type and the file size limit for that category - documents, images, audio and video each have different ceilings, and exceeding one produces this error rather than a clearer size-specific message.
Template errors: the 132xxx family
Every error in this group fails identically for every recipient. If a template send is failing for one person, it is failing for all of them.
| Code | Meaning | Fix |
|---|---|---|
| 132000 | Parameter count mismatch | You supplied a different number of variables than the template declares. Count the {{1}} placeholders including any in the header and buttons - those are counted separately from the body. |
| 132001 | Template does not exist | Name or language mismatch. Template names are case-sensitive, and the language code must match exactly - en and en_US are different templates. |
| 132005 | Hydrated text too long | Your variable values pushed the assembled message past the length limit. Truncate long values - product names and addresses are the usual culprits. |
| 132007 | Format character policy violated | A parameter contains newlines, tabs, or more than four consecutive spaces. Strip whitespace from interpolated values. |
| 132012 | Parameter format mismatch | The value does not match the format the template expects, commonly for currency and date-time parameters which need structured objects rather than strings. |
| 132015 | Template paused | Quality dropped due to blocks and reports. It resumes automatically after a cooling period - repeated pauses lead to permanent disabling. |
| 132016 | Template disabled | Permanently disabled for quality. It cannot be re-enabled - create a new template with better-targeted content. |
The parameter counting trap behind 132000
132000 is far more common than it should be because header, body and button parameters are counted in separate component arrays. A template with one variable in the header and two in the body needs a payload with a header component containing one parameter and a body component containing two - not a flat list of three. Sending three body parameters against that template produces 132000 even though the total count is right.
Template quality is a slow-motion failure
132015 and 132016 are the visible end of a process that starts much earlier. Meta assigns each template a quality rating driven by blocks and reports from recipients. Ratings degrade quietly, and by the time you see a pause, the underlying problem has been running for weeks. Monitor template quality in the WhatsApp Manager rather than waiting for the error - a template that has slipped to medium quality is a warning you still have time to act on.
Rate limits and messaging tiers: 130429, 131048, 131056
130429 - Rate limit hit
You exceeded the API call throughput for your account. Back off exponentially and retry; do not hammer, because sustained overage extends the restriction. If you hit this consistently rather than in bursts, you need a queue that paces sends rather than a loop that fires as fast as the network allows.
131048 - Spam rate limit hit
Different and more serious. This is not throughput - it is a quality signal. Meta has restricted your sending because your messages are generating blocks and reports at a rate it considers harmful. Retrying does nothing; the fix is to send fewer, better-targeted messages to people who opted in.
131056 - Business and account pair rate limit
Too many messages to one specific recipient in a short period. This protects individual users from being flooded by a single business. Space your messages to a given contact, and check for a loop that is resending on failure.
Messaging tiers: the limit behind the limit
Business-initiated conversations are capped by tier, and unverified accounts start low. Growth through the tiers is automatic and depends on volume plus a good quality rating.
| Tier | Unique customers per 24h (business-initiated) |
|---|---|
| Unverified | 250 |
| Tier 1 | 1,000 |
| Tier 2 | 10,000 |
| Tier 3 | 100,000 |
| Tier 4 | Unlimited |
Two things about tiers catch teams out. First, the cap counts unique customers, not messages - a campaign to 2,000 people fails at Tier 1 regardless of how few messages each person receives. Second, tiers can go down. A quality drop demotes you, and a campaign sized for your previous tier will start failing partway through.
Authentication and permissions: 190, 10, 200, 100
| Code | Meaning | Usual cause |
|---|---|---|
| 190 | Access token expired or invalid | A temporary token was used in production - see below |
| 10 | Permission denied | The app lacks whatsapp_business_messaging |
| 200 | Permission error | The system user has no role on the WhatsApp Business Account |
| 100 | Invalid parameter | Generic malformed request - read details, it names the field |
| 368 | Temporarily blocked for policy violations | Account-level restriction; check WhatsApp Manager for the violation |
The 190 that appears exactly 24 hours after launch
This has a signature timing. The temporary access token generated in the Meta developer dashboard for testing expires after 24 hours. Ship with it and your integration works perfectly through your first day of testing, then fails overnight with 190 and no other change.
The fix is a permanent token from a System User: Business Settings, System Users, create or select one, assign it a role on your WhatsApp Business Account, and generate a token with whatsapp_business_messaging and whatsapp_business_management. Store it in a secrets manager. Never in the repository - Meta invalidates tokens it finds in public sources, which is a second and entirely separate way to meet error 190.
Quick reference: symptom to cause
| What you observe | Most likely code | First thing to check |
|---|---|---|
| Replies work, then stop after a while | 131047 | 24-hour window closed - switch to a template |
| Everything worked yesterday, all fails today | 190 | Temporary token expired - issue a System User token |
| Fails for one recipient, fine for others | 131026 | Number format - drop the leading zero and the + |
| One template fails for everyone | 132000 / 132001 | Parameter count per component, or name/language mismatch |
| Campaign works then stops partway | Tier limit / 130429 | Unique-customer cap for your messaging tier |
| Marketing silently underdelivers | 131049 | Engagement-based suppression - segment your list |
| Sends fail only for long values | 132005 | Hydrated template exceeded length - truncate variables |
Three practices that prevent most of these
- Store the last inbound timestamp per contact. Nearly every 131047 is preventable with a comparison you can do before calling the API at all.
- Normalise phone numbers on write, not on send. Strip
+, spaces, punctuation and the national leading zero when the number enters your system, so every downstream send is already correct. - Log the full error object with the
fbtrace_id. Code alone is not enough to diagnose, and the trace ID is the only thing Meta support can investigate.
When inbound messages never arrive: webhook problems
Every error so far concerns messages you send. A second, quieter failure class is messages you never receive - a customer replies and your system has no idea.
The verification handshake
Meta verifies your webhook with a GET request carrying three query parameters:
GET /webhook?hub.mode=subscribe&hub.challenge=1158201444&hub.verify_token=YOUR_TOKENYou must compare hub.verify_token against your configured value and, if it matches, return hub.challenge as plain text with a 200. Returning JSON, returning the whole query string, or returning it with a 201 all fail verification.
app.get('/webhook', (req, res) => {
if (req.query['hub.verify_token'] === process.env.VERIFY_TOKEN) {
return res.status(200).send(req.query['hub.challenge']);
}
res.sendStatus(403);
});Verified, but no events arrive
Verification and subscription are separate steps, exactly as they are on other platforms. In the App Dashboard under WhatsApp -> Configuration, you must subscribe to specific webhook fields - messages being the essential one. A verified callback URL with no field subscriptions receives nothing forever.
Also confirm the app is subscribed to your WhatsApp Business Account, not merely configured. These are separate associations, and a missing one produces silence with no error anywhere.
Meta disabled your webhook
If your endpoint returns errors or times out repeatedly, Meta stops delivering and marks the subscription inactive. Nothing tells you at runtime; you simply stop receiving messages. Check the Webhooks section in the App Dashboard for a disabled state, and check the alerts in Business Manager.
The prevention is the same pattern as everywhere else in this guide: acknowledge with 200 immediately, then process asynchronously. A webhook handler that calls an LLM before responding will eventually be disabled under load.
Duplicate inbound messages
Meta retries deliveries it believes failed, so the same message can arrive more than once. Deduplicate on the message id field, which is stable across retries. Without it, a slow handler produces duplicate tickets, duplicate CRM records and duplicate bot replies.
Media upload and download failures
Media has its own error surface and its own set of limits, and it is where integrations most often work in testing and fail on real customer content.
Size and type limits
| Type | Approximate limit | Common formats |
|---|---|---|
| Image | 5 MB | JPEG, PNG |
| Document | 100 MB | PDF, Office formats, plain text |
| Video | 16 MB | MP4, 3GPP |
| Audio | 16 MB | AAC, MP4, MPEG, AMR, OGG |
| Sticker | 100 KB static | WebP |
Verify current limits against Meta's documentation before relying on them - they change. Exceeding one produces a generic failure rather than a helpful size-specific message, so validate on your side before uploading.
MIME type must match the actual file
Sending image/jpeg for a file that is actually a PNG fails, and this happens more often than expected because many systems infer the type from the filename extension rather than the bytes. Detect the real type from the file content, not the name.
Media IDs expire
Uploaded media returns an ID valid for a limited period - around 30 days. Storing media IDs and reusing them months later fails. For content you send repeatedly, either re-upload periodically or send by link instead, which shifts hosting to you and avoids the expiry entirely.
Downloading inbound media requires a second call, and a token
An inbound media message contains an ID, not the file. You call the media endpoint to get a URL, then fetch that URL with your access token in the Authorization header. Fetching the URL without the header returns 401, which is the single most common inbound-media mistake. The URL is also short-lived, so download promptly rather than storing it.
Avoiding this layer altogether
Most of the errors above are not really errors. They are WhatsApp's rules expressed as HTTP failures - the 24-hour window, template approval, messaging tiers, quality ratings, number formatting, token lifecycles. Building directly on the Cloud API means encoding every one of those rules yourself and rediscovering the ones you missed in production.
Conferbot's WhatsApp integration manages the window state, template selection, retry behaviour and rate pacing for you: you build the conversation in a visual flow editor and the platform decides whether a given message can go free-form or needs a template. The same flow also runs on Telegram, Instagram, Messenger and a website widget, each with its own equivalent set of rules handled the same way.
Start free with Conferbot - the free plan includes 600 conversations a month and needs no credit card, so you can have the same flow running on a second channel this afternoon.
That trade is worth weighing carefully now rather than later, because from 1 October 2026 the cost side changed too - service messages are billable, and message count is the cost driver. Our guide to the October 2026 billing change covers what that means for your flows and what to do before the deadline.
Was this article helpful?
Build and deploy in 10 minutes. No coding needed.
WhatsApp Cloud API Error Codes FAQ
Everything you need to know about chatbots for whatsapp cloud api error codes.
About the Author
The Conferbot team writes about building, deploying, and improving AI chatbots.
View all articles