Description
What is HTTP status codes?
HTTP status codes are the three-digit numbers at the start of every HTTP response. The first digit gives the class: 2xx means the request succeeded, 3xx a redirect, 4xx a problem with the request — bad input, missing authentication, no permission, too many calls — and 5xx a failure on the server's side. On messaging APIs the handful that matter are 200, 400, 401, 403, 404, 429, 500 and 503.
On the WhatsApp Cloud API the status is only half the story. Every failure carries a JSON error object with Meta's numeric code, a message, error_data.details and an fbtrace_id, and Meta recommends building error handling around that code and its details, because the HTTP status is coarse. In practice an invalid parameter (error 100), a missing required parameter (131008) and a throughput limit (130429) can all come back as 400, while an expired token (error 190) typically arrives as 401 and missing permissions (error 10) as 403.
HTTP status codes differ from API Error Codes: the status is the generic, protocol-level outcome every HTTP client understands, while the error code is Meta's specific reason. Use the status to choose the broad branch — success, client error, server error — and the error code to choose the action: retry later, fix the payload, refresh the token or switch to a template. Some failures never appear in the HTTP response at all: an undeliverable number (131026) arrives later as a failed status on the webhook.
Key takeaways
- HTTP status codes are the three-digit result on every response: 2xx success, 4xx a problem with the request, 5xx a server-side failure.
- On the WhatsApp Cloud API, Meta recommends building error handling around the
codeanddetailsin the response body. - Rate-limit errors such as 130429 typically arrive as HTTP 400, not 429, so a client that only retries 429 misses them.
- Retry 5xx responses, timeouts and rate limits with backoff; for other 4xx errors, fix the request instead of resending it.
- A 200 from the messages endpoint means accepted, not delivered — delivery and failures arrive later on the statuses webhook.
Properties
HTTP status codes: key facts and limits
- 200 OK
- Accepted — for messages, not yet delivered
- 400 Bad Request
- Invalid input — and, on Meta, many rate limits
- 401 Unauthorized
- Missing, invalid or expired token (e.g. error 190)
- 403 Forbidden
- Valid token, missing permission or asset access (e.g. error 10)
- 404 Not Found
- Wrong ID or path, or an expired media download URL
- 429 Too Many Requests
- The generic rate-limit status — don't rely on it with Meta
- 500 / 503
- Server error / unavailable — retry with backoff
- Meta's guidance
- Build handling around error code and details
Usage
HTTP status codes in code
// Transient Cloud API codes worth retrying with backoffconst RETRYABLE = new Set([4, 80007, 130429, 131000, 131016, 131056]);function classify(httpStatus, body) {const code = body?.error?.code;if (httpStatus >= 200 && httpStatus < 300) return "ok";if (httpStatus === 401 || code === 190) return "refresh-token"; // retrying won't helpif (httpStatus === 403) return "fix-permissions";if (RETRYABLE.has(code)) return "retry-with-backoff"; // often HTTP 400!if (httpStatus === 429 || httpStatus >= 500) return "retry-with-backoff";return "fix-request"; // 100, 131008, 132000…}
Status first, Meta's error code second: a 400 can be a rate limit you should retry.
Mechanics
How does HTTP status codes work?
step 1 — Read the status class first
2xx: success, parse the body. 4xx: the request, token or account needs attention. 5xx or a timeout: the request may or may not have been processed.
step 2 — Then read Meta's error code
Parse
error.codeanderror_data.details. The code decides the action; the status only narrows the options.step 3 — Retry only what can succeed later
Retry 500, 503, timeouts and rate-limit codes (4, 80007, 130429, 131056) with Exponential Backoff and jitter. Never retry validation errors such as 100 or 131008 unchanged.
step 4 — Escalate auth and permission errors
401 with error 190 needs a new or refreshed token; 403 with error 10 or 200–299 needs a permission or asset access. Retries will not fix either — alert a person.
step 5 — Handle the asynchronous half
A 200 means accepted. Delivery failures such as 131026 arrive later as
failedstatuses on the webhook, so error handling needs both paths.
Caveats
Common mistakes with HTTP status codes
Retrying every non-200
Resending a 400 for a missing parameter repeats the failure and eats rate limit. Retry only 5xx, timeouts and documented transient codes; send the rest to a person or a dead-letter queue.
Waiting for a 429 that never comes
Meta's throughput and Rate Limiting errors (130429, 80007, 4) usually come back as 400. Classify by
error.code, or your client will treat them as permanent and drop messages.Treating 200 as delivered
The messages endpoint returns 200 once Meta accepts the request. Undeliverable numbers and closed windows can still fail afterwards — watch the statuses webhook.
Retrying a timeout blindly
If the connection dropped after Meta accepted the message, a blind retry sends a duplicate. Record each send under your own ID and reconcile with webhooks before resending.
Returning errors to Meta's webhooks
Your own endpoint's status matters too — this is Webhook Acknowledgement: anything but 200 makes Meta retry the webhook for up to seven days. Acknowledge with 200 first, then process from a queue.
Notes
Best practices for HTTP status codes
- Log status,
error.code,error_data.detailsand the FB Trace ID together for every failure. - Cap retries and move what still fails to a dead-letter queue for review.
- Alert on a rising rate of 401 or 403 — it usually means a token or permission was revoked.
- Add jitter to backoff so a burst of failures does not retry in lockstep.
Why it matters
Why does HTTP status codes matter?
Getting retries wrong is one of the most expensive bugs in a messaging integration. Retrying a 400 for a bad payload repeats the failure thousands of times and burns rate limit; not retrying a 503 or a throughput error drops messages that would have gone through a second later; and retrying a request whose first attempt actually succeeded sends the customer a duplicate. A clear policy — status class first, Meta's error code second, deduplication always — keeps campaigns flowing and support tickets down.
Example
Example: A festive broadcast that hit the limit
A Pune electronics retailer's sender fires 120 requests per second at a number with the default throughput of 80 messages per second. Roughly a third of requests come back as HTTP 400 with Error 130429 (Rate Limit Hit). The first version of its client treated every 400 as a bad request and marked those customers as failed. After switching to classify by error.code, the same responses go to a retry queue with exponential backoff and jitter, the sender is paced below the number's throughput, and the next campaign completes without a single message dropped.
Questions
HTTP Status Codes FAQs
- Does the WhatsApp Cloud API return 429 for rate limits?
- Usually not. Throughput and rate-limit errors such as 130429 and 80007 typically come back as HTTP 400 with the specific code in the body, so classify responses by
error.coderather than waiting for a 429. - What is the difference between 401 and 403?
- 401 means the API could not authenticate you — the token is missing, invalid or expired, as in Error 190 (Access Token Invalid). 403 means it knows who you are but you lack the permission or access to that asset (error 10 or 200–299).
- Which HTTP errors are safe to retry?
- 500, 503, timeouts and rate-limit errors, with exponential backoff and a retry cap. Do not retry validation errors (most 400s), 401 or 403 unchanged — fix the request, token or permission first.
- Does a 200 response mean my WhatsApp message was delivered?
- No. It means Meta accepted the request and returned a message ID. Sent, delivered, read or failed arrive later on the statuses webhook, matched by that ID.