Errors & limits
How the WhatsApp API reports failures — the response envelope, the actionable send-error codes, the 429 rate-limit shape — and every hard limit that governs media, templates, broadcasts and the 24-hour window. Read this alongside Webhooks & events, where the same failures resurface asynchronously in whatsapp.message.status.
The response envelope
Every WhatsApp endpoint returns the standard Telenow envelope. Success carries data (a few acknowledgements — mark-read, pause/cancel on the app key, template delete — return just success); failure carries a human-readable error string and an HTTP status code.
{ "success": true, "data": { "wamid": "wamid.HBgL…" } }
{ "success": false, "error": "This contact hasn't messaged you in 24 hours — send an approved template to reopen the conversation." }
| Status | When | What to do |
|---|---|---|
400 | Malformed body, wrong/multiple content fields, or an actionable send error (a plain-English sentence — below) | Fix the request as the message says |
401 | Missing or invalid key: Invalid or revoked API key, API key creator is no longer active, or Access token is required (no key sent, or an org key on a login-only route) | Check Authorization: Bearer vai_app_… or X-API-Key: vai_live_… — see Authentication |
403 | App key lacks the required scope; or, with an org API key: another org's id in the path (This API key is scoped to a different organization.), a viewer key on a write (This API key's role ('viewer') is read-only on this endpoint.), or the key's creator lacks the role | Grant the scope (Scopes), or use a key with the right org and role |
404 | Unknown channel, template, campaign, or media id | Check the id belongs to your org |
404 | Native WhatsApp is not enabled (app key), or WhatsApp Hub is not enabled / WhatsApp is not enabled (org key), on every route of that surface | WhatsApp isn't enabled on this Telenow deployment — a platform-wide flag, not a bad id. Contact your administrator |
409 | A campaign isn't in a state that allows the action, or a request with the same Idempotency-Key is still running | Re-read the campaign; or wait and retry (Retry-After: 5) |
413 | Upload exceeds the media cap for its type, or a body over 5 MB sent with Idempotency-Key | Shrink or re-encode — media caps |
415 / 422 | A body that isn't JSON or has the wrong types — e.g. a mediaId that isn't a UUID. These come back as plain text, not the JSON envelope | Fix the body's shape |
429 | Rate limit exceeded | Back off using retryAfter — rate limits |
502 | WhatsApp or the number's provider refused the request, or Telenow refused a send it knows can't work (a caption on audio, media on a non-Cloud number, a STOP'd number). Body: { "success": false, "error": "<the provider's message>", "code": "provider_error" } | Read error — it's the provider's own explanation |
The send endpoint validates the body strictly:
POST /sendneeds exactly one content field (message—bodyon the org-key route — ormediaId,location,reaction,contacts,interactive). Zero or two of them is a400before the message ever reaches WhatsApp.
Send error codes
When the failure matches one of the known Meta codes in the table below, Telenow surfaces it as an actionable 400 on the send call — you don't have to wait for a webhook to know it failed. The 400's error is a plain-English sentence explaining the fix; it doesn't include the code number. Any other failure returns 502 with code: "provider_error" and the provider's own message in error (see the status table). The same codes also appear in the errors array of a whatsapp.message.status event when a message fails after the API already returned a wamid (async delivery failures).
| Code | Meaning | Fix |
|---|---|---|
131042 | Payment issue — the account can't be billed for this message | Add or fix a payment method in Meta Business Manager |
131047 | 24-hour customer service window has closed | Send an approved template instead of free-form text |
131026 | Message undeliverable — recipient isn't on WhatsApp or is restricted | Verify the number is a real WhatsApp user; drop it from retries |
131056 | Sending too fast to this recipient (pair rate limit) | Back off and retry after a short delay |
368 / 131031 | Number restricted for a policy violation | The number/account is limited by Meta — resolve the policy issue in Business Manager |
132000, 132001, 132005, 132007, 132012, 132015, … | Template problems — each gets its own message: the wrong number of values, no template by that name and language, a value too long, a policy breach, a value in the wrong format, a template paused for quality | Check the template is APPROVED and your variables/components match its placeholders |
On the variables path of a template send, a template problem comes back as a 502 whose error starts whatsapp template send failed (400 Bad Request): followed by the same explanation.
Example — sending free-form text after the window closed:
curl -X POST https://api.telenow.ai/api/app-whatsapp/send \
-H "Authorization: Bearer vai_app_…" \
-H "Content-Type: application/json" \
-d '{ "channelId": "9f2c7b1e-…", "to": "+919876543210",
"message": "Just following up!" }'
{ "success": false, "error": "This contact hasn't messaged you in 24 hours — send an approved template to reopen the conversation." }
The fix is a template send, which is allowed outside the window:
curl -X POST https://api.telenow.ai/api/app-whatsapp/send-template \
-H "Authorization: Bearer vai_app_…" \
-H "Content-Type: application/json" \
-d '{ "channelId": "9f2c7b1e-…", "to": "+919876543210",
"template": "order_update", "language": "en_US", "variables": ["Asha", "#1234"] }'
{ "success": true, "data": { "wamid": "wamid.HBgLMTIxNTU1NTk4NzYVAgERGBI0Rjc5…" } }
Rate limits
Two limits apply, and a request has to fit both:
- Per IP address — every key: 2,000 requests per 15 minutes for any request that isn't signed in to the dashboard, app keys and org API keys alike. Over it you get
{ "success": false, "error": "Too many requests, please try again later", "retryAfter": 412 }—retryAfteris the seconds until the 15-minute window resets, so it can be minutes. - Per app — app keys only: roughly 20 requests/second with a burst of 60 for each installed app:
{ "success": false, "error": "Data API rate limit reached — slow down", "retryAfter": 1 }.
Both 429s also send a Retry-After header. Respect it before retrying, and serialize sends per recipient to avoid the per-pair 131056. Request bodies are capped at 2 MB on JSON routes; the media upload route allows up to 101 MB and the template-media route 17 MB (the file itself is still bound by the per-type media caps below). The org-key limits are listed in full under Authentication & channels.
Safe retries with Idempotency-Key
Send an Idempotency-Key header (any unique string, such as a UUID) on a POST, and a retry with the same key and body within 24 hours returns the original successful response — marked Idempotent-Replay: true — instead of sending twice. The same key with a different body returns 422; the same key while the first request is still running returns 409 with Retry-After: 5. With the header, the request body is limited to 5 MB (413 body too large), so leave it off large media uploads. Without the header, dedupe on the returned wamid and only retry when you did not receive one.
Media caps
Uploads to POST /api/app-whatsapp/channels/{id}/media (or the org-key …/whatsapp-hub/channels/{channelId}/media) are capped per media type (taken from the upload's MIME type; image/webp counts as a sticker). Over the cap returns 413.
| Type | Max size |
|---|---|
| Image | 5 MB |
| Audio | 16 MB |
| Video | 16 MB |
| Sticker | 500 KB |
| Document | 100 MB |
Template header media (POST /channels/{id}/templates/media) is separately capped at 16 MB and limited to image/jpeg, image/png, video/mp4, application/pdf. See Media and Templates.
Template limits
Enforced at template creation and edit time (POST / PATCH template endpoints, scope whatsapp:templates). A violation returns 400 before the template is submitted to Meta.
| Rule | Limit |
|---|---|
| Body text | ≤ 1024 characters |
| Footer text | ≤ 60 characters |
| Header text | ≤ 60 characters |
| Button text | ≤ 25 characters |
| Buttons per template | ≤ 10 |
| Body count | Exactly one non-empty BODY (marketing/utility) |
| Placeholders | Contiguous {{1}}…{{N}} in the body text — no gaps (Meta also expects an example for each; Telenow doesn't check those) |
name | Lowercase letters, digits and _, ≤ 512 chars |
category | MARKETING · UTILITY · AUTHENTICATION |
Authentication templates follow their own shape rules instead of the length limits. Editing a template resets it to PENDING re-approval (a template that's still PENDING can't be edited); name and language are immutable. Full component shapes are in Templates.
Not yet supported: carousel and limited-time-offer templates, and one-tap OTP buttons (authentication templates support COPY_CODE only).
Broadcast limits
Broadcasts are bounded differently on each surface:
| Rule | App key (POST /campaigns, scope whatsapp:campaign) | Org API key (/whatsapp-campaigns) |
|---|---|---|
| Recipients | ≤ 5,000 per campaign | ≤ 20,000 per upload (uploads can repeat); ≤ 5,000 per saved-audience call |
| Active campaigns | 50 per app | No cap |
| Throttle | 60 messages/minute by default (throttle_per_min, 1–6,000); at most ~400/minute actually sent | Same |
Beyond these, your real ceiling is Meta's messaging tier for the number (e.g. TIER_1K, TIER_10K) — watch whatsapp.account.health for tier changes.
Which numbers support what
A WhatsApp number in Telenow is either a Meta Cloud number (native — "set up for you" — or connected through your own Meta app), a partner number (GupShup, Plivo, AiSensy), or a WhatsApp Web number (linked by QR).
| App key | Org API key | |
|---|---|---|
| Text | Meta Cloud; WhatsApp Web with the whatsapp:web scope | Every number |
| Media, interactive, location, contacts, reactions | Meta Cloud | Meta Cloud |
| Templates | Meta Cloud | Meta Cloud and partner numbers |
| Broadcasts | Meta Cloud | Meta Cloud and partner numbers |
| Read conversations | Meta Cloud | Every number |
| Template management, account health, business profile | Meta Cloud | Meta Cloud |
Webhook events (received, status) | Meta Cloud numbers only, whichever key you use |
Meta also limits how often you can change a number's display name — check Meta Business Manager before renaming.
The 24-hour window
WhatsApp only allows free-form messages (text, media, interactive, location, reaction, contacts) within 24 hours of the customer's last inbound message. Outside that window you must send a pre-approved template — free-form sends fail with Meta code 131047, either right away (Telenow's 400) or as a failed status event.
- Every inbound
whatsapp.message.receivedresets the 24-hour clock. - Templates are always allowed, in or out of the window — that's how you re-open a conversation.
- Reading history via threads shows
lastInboundAt(last_inbound_aton the org-key route); use it to decide whether the window is open before sending free-form.
customer replies ──► 24h window OPEN ──► free-form text OK ──┐
│ 24h elapse, no reply
▼
window CLOSED ──► free-form → 131047
│
└─► send a template to re-open
Reading failure detail from webhooks
A send can succeed synchronously (you got a wamid) yet fail later at Meta — for example, the number turned out to be undeliverable. That surfaces only as a whatsapp.message.status event with status: "failed" and the same numeric codes in its errors array:
{
"event": "whatsapp.message.status",
"wamid": "wamid.HBgLMTIxNTU1NTk4NzYVAgARGBI3Q0Ez…",
"status": "failed",
"recipient": "+919876543210",
"errors": [ {
"code": 131026,
"title": "Message undeliverable.",
"message": "Message undeliverable.",
"error_data": { "details": "Message failed to send because the recipient's phone number is not a WhatsApp phone number." },
"href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/"
} ]
}
Match the wamid to your original send, look the code up in the table above, and take the same corrective action you would for a synchronous 400. Read error_data.details for the actionable specifics — it's more precise than the generic title. See Webhooks & events for wiring, signatures and dedupe.
Account health
Many send failures are downstream of your account's state — an unverified business, a low quality rating, or no payment method. Check a Meta Cloud number's live health with your org API key (any role, including viewer) or a dashboard login:
curl "https://api.telenow.ai/api/orgs/{orgId}/whatsapp-cloud/channels/{channelId}/health" \
-H "X-API-Key: vai_live_…"
{ "success": true, "data": {
"phone": { "quality_rating": "UNKNOWN", "whatsapp_business_manager_messaging_limit": "TIER_1K", "name_status": "PENDING_REVIEW" },
"waba": { "account_review_status": "APPROVED", "business_verification_status": "verified",
"health_status": { "can_send_message": "BLOCKED", "entities": [ … ] } },
"tokenStatus": "active",
"warnings": [
{ "code": "wa_payment_method", "level": "error",
"title": "There's a problem with your WhatsApp payment method",
"detail": "There is an error with the payment method. … Please add a new payment method to the account. (Meta error 141006, on WhatsApp Business Account.)",
"action": "Open Meta Business Manager" }
],
"callingReadiness": { "canEnable": false, "blockers": [ … ], "advisories": [ … ],
"callingOn": null, "mediaPlane": true }
} }
phone/waba— the raw Meta health fields (quality rating GREEN/YELLOW/RED/UNKNOWN, messaging limit, review and business-verification status). Meta deprecatedmessaging_limit_tierin favour ofwhatsapp_business_manager_messaging_limit, which reports your business portfolio's limit; both are read, newest first. An absent limit means Meta hasn't rated the account — not that it passes.wabaId/metaBusinessId— the WhatsApp Business Account and Meta business behind the number. The response can also carrynotes.tokenStatus—active, orrevokedif Meta pulled access (you'll need to reconnect the number).warnings— a ready-made, human-readable list; each has acode, alevel(info/warn/error), atitle, adetail, and an optionalaction. The dashboard renders these as the account-health banner on the channel. Codes includewa_payment_method,wa_token_revoked,wa_quality_rating,wa_business_unverified,wa_account_review,wa_account_blocked,wa_account_notice,wa_name_pending_review,wa_messages_webhook_missingandwa_template_webhook_missing. On native numbers, anything Meta reports insidehealth_status.entities[]— botherrors[]and the advisoryadditional_info[]— is flattened into this list, including notices on an entity that otherwise readsAVAILABLE.callingReadiness— native numbers only; see Calling errors.
The same signals also arrive asynchronously as whatsapp.account.health webhook events — a nudge to re-read this endpoint. A payment method is the most common blocker: without one, sends fail with 131042 — add it in Meta Business Manager (Meta bills you directly).
Calling errors
Enabling WhatsApp calling has prerequisites that Meta only reveals by refusing. The toggle checks them before asking Meta, so you get the reason rather than a bare rejection — callingReadiness.blockers on the health endpoint is the same list.
| Meta code | Our code | What it means | Who fixes it |
|---|---|---|---|
138015 | wa_calling_messaging_limit | Your business portfolio's messaging limit is under 2,000/24 h. It rises with business verification and sending history — not by adding numbers | you |
138018 | wa_calling_webhook_missing | No app subscribed to your WABA subscribes to the calls webhook field, or the account isn't subscribed to us at all | us — contact support |
141006 | wa_payment_method | No valid payment method on the WABA. Blocks business-initiated conversations; shown as a warning, and it does not by itself stop the toggle | you |
131044 | — | The same payment problem, arriving as an error webhook during a live call rather than as a refusal to enable | you |
| — | wa_calling_media_off | The server can't carry call audio yet, so calls are declined immediately rather than answered. A warning, not a refusal | us |
| — | wa_token_revoked | Meta pulled access — reconnect WhatsApp | you |
blockers stop the toggle; advisories are real and shown but never fail a save Meta would have accepted. A blocker is only ever something Meta itself documents as rejecting the request, so the pre-flight can't forbid something Meta would allow.
Related
- Webhooks & events — receive
message.statusfailures and account-health changes. - Send messages · Templates · Media · Broadcasts.
- WhatsApp API — endpoint index.
- Authentication · Scopes & security.