Skip to content

Playbook · 6 steps

Retry Policy

Also called: Retry strategy · Retry rules

6steps

Level
Practitioner
Reading time
About 6 min

Reviewed

Definition
The rules that decide which failed API calls to try again, how many times and within what budget, and which errors must never be retried.

01 · How it works, in 6 steps

How does a retry policy work?

  1. 1

    Classify every failure

    Map errors to retry, retry-later, fix-then-retry and never-retry. Branch on the Graph API error.code in the JSON body rather than the HTTP status alone, and treat timeouts as transient but with an unknown outcome.

  2. 2

    Set an attempt cap and a deadline

    Allow a few attempts — three to five is common — inside an overall time limit set by what the work is worth: seconds for an OTP, minutes for a dispatch notice, hours for a non-urgent report.

  3. 3

    Space attempts with backoff and jitter

    Delay each retry exponentially with random jitter so clients that failed together do not retry together, and honour waits the error implies, such as 24 hours for 131049.

  4. 4

    Enforce a retry budget

    Track retries as a share of all requests and stop retrying when the share passes a threshold such as 10%. When most calls are failing, more retries only add load.

  5. 5

    Make retries safe

    Only retry operations that are idempotent or carry an idempotency key. For sends, carry your own ID in biz_opaque_callback_data and check status webhooks before resending after a timeout.

  6. 6

    Give up loudly

    When attempts or budget run out, move the job to a dead-letter queue with the last error and alert on it, instead of dropping it silently.

02Try it

Hands-on: use the controls to work through it yourself.

Step through a retry policy until it gives up

6 / 6

Retries exhausted

t = 10.7 s

Gave upDead-letter the job and alert
  1. Attempt 1 at 0 ms: failed.
  2. Attempt 2 at 173 ms, after waiting 173 ms: failed.
  3. Attempt 3 at 2.08 s, after waiting 1.91 s: failed.
  4. Attempt 4 at 3.85 s, after waiting 1.76 s: failed.
  5. Attempt 5 at 10.7 s, after waiting 6.87 s: failed.
  6. Dead-letter the job and alertafter 5 attempts · t = 10.7 s

The delay formula

delayn = min(cap, base × factorn)

All 4 retries are spent (5 attempts in 10.7 s), so the client stops: Dead-letter the job and alert.

24 clients, same outage · retry n = 3

Full jitter spreads their retries across the window: at most 5 land together, so the recovering server is not flattened.

A send failing with a transient error gets four retries, spaced by capped exponential backoff with full jitter. Step through the attempts, switch jitter off to see the herd form, and watch the policy stop.

Gave up after 5 attempts at 10.7 s: Dead-letter the job and alert.

03What is a retry policy?

A retry policy is the set of rules your code follows when a call fails: whether to try again at all, how many attempts to allow, how long the whole effort may take, and when to give up and hand the job to a dead-letter queue or a person. It is the decision layer of error handling. Exponential backoff — how long to wait between attempts — is a separate mechanism that the policy uses.

The core of a good policy is classification. Some failures are transient: a timeout, a dropped connection, an HTTP 5xx, or a rate limiting error from the WhatsApp Cloud API such as error 130429 (rate limit hit), returned when the number's throughput is exceeded, or 131056 (too many messages to the same recipient too quickly). Waiting and retrying can fix these. Others are permanent for that request: an invalid parameter (100), a free-form message outside the customer service window (131047), template parameters that do not match (132000), a template that does not exist (132001) or a policy block (368). Retrying those changes nothing except your error count.

A third group needs an action before any retry. An expired or invalid access token (190) needs a new token first. A per-user marketing limit (131049) should not be retried for at least 24 hours. A paused template (132015) needs the template to recover or a substitute. A policy also needs limits — a maximum number of attempts per request and a retry budget across all requests — because retries are extra load, and they arrive exactly when a dependency is struggling.

Key takeaways

  • A retry policy decides whether a failed call is tried again, how many times, and inside what overall time and load budget.
  • Retry transient failures — timeouts, 5xx responses, throughput error 130429 — and never retry errors caused by the request itself.
  • Errors such as 100 (invalid parameter), 131047 (re-engagement) and 132000 (parameter mismatch) fail identically on every attempt.
  • Cap attempts per request and keep retries under about 10% of total traffic, so a struggling dependency is not buried in retries.
  • The policy is the go/no-go decision; exponential backoff and jitter only set the delay between the attempts it allows.

04 · Key facts

A retry policy: key facts and limits

Retry (transient)
Timeouts, 5xx, 130429, 131000, 131016
Never retry as-is
100, 131047, 132000, 132001, 368
Act first, then retry
190: new token · 132015: wait for the template
Per-user marketing limit (131049)
Wait at least 24 hours
Common attempt cap
3–5 attempts per request
Common retry budget
Retries at most 10% of requests
Not your policy
Meta retries failed webhooks for up to 7 days

05 · In code

A retry policy in code

// Turn a failed Cloud API call into an action.
const RETRY = new Set([1, 2, 4, 80007, 130429, 131000, 131016, 131057]);
const NEVER = new Set([100, 131047, 131051, 132000, 132001, 368]);
export function classify({ status, error, timedOut }) {
if (timedOut) return { action: "check-status-then-retry" }; // outcome unknown
const code = error?.code;
if (code === 190) return { action: "refresh-token-then-retry" };
if (code === 131049) return { action: "retry-after", waitMs: 24 * 3600 * 1000 };
if (code === 131056) return { action: "slow-down-for-this-recipient" };
if (code === 132015) return { action: "hold-until-template-active" };
if (RETRY.has(code) || status >= 500) return { action: "retry-with-backoff" };
if (NEVER.has(code)) return { action: "dead-letter" };
return { action: "dead-letter", unknownCode: code }; // do not guess
}

One table, used by every sender. Unknown codes go to the dead-letter queue: new error codes are more often permanent than transient.

06 · Why it matters

Why does a retry policy matter?

Retries are the cheapest reliability feature you can add and the easiest to get dangerously wrong. Without them, every network blip becomes a lost order update. With a naive 'retry everything five times', permanent errors waste capacity and delay alerts, throttling errors are hammered harder, and an outage turns into a retry storm that keeps the service down. A deliberate policy recovers transient failures automatically and sends everything else straight to the right handling.

07 · Mistakes to avoid

Common mistakes with a retry policy

  • Deciding on the HTTP status alone

    Graph API errors carry the detail in the JSON error.code and error_data.details; two responses with the same status can need opposite handling. Read the code before deciding.

  • Retrying the request's own mistakes

    Invalid parameters, closed service windows and template mismatches fail the same way every time. Retrying them burns throughput and hides the bug; dead-letter them immediately.

  • Retries without a budget

    When a dependency is down, unbounded retries multiply traffic and keep it down. Cap attempts per request and retries as a share of all traffic, and let a circuit breaker stop calls entirely while the dependency recovers.

  • Blind retries after a timeout

    A send that timed out may have been delivered. Retrying without a correlation check produces duplicate messages, and every duplicate that is delivered is billed again.

  • Stacking retries at every layer

    If the HTTP client, the worker and the queue each retry three times, one failure becomes 27 calls. Retry at one layer and make the others fail fast.

08Example: Sorting a festive campaign's failures

A Tiruppur apparel brand sends 400,000 marketing templates over a Diwali evening and about 2,000 calls fail. The retry policy sorts them. Most are 130429 throughput errors from the opening burst, retried with jittered backoff and accepted within minutes. A few hundred are 131049 per-user marketing limits, scheduled for no earlier than 24 hours later instead of being hammered. A batch of 132000 errors from one segment's broken variable mapping goes straight to the dead-letter queue and pages the developer. A handful of timeouts are checked against status webhooks before any resend. Nothing that could not succeed is retried, and nobody receives the offer twice. (Figures are illustrative.)

09Retry Policy FAQs

Which WhatsApp API errors should be retried?+
Retry transient failures: timeouts, connection errors, HTTP 5xx and throttling codes such as 130429 and 131056, always with backoff. Errors such as 100, 131047, 132000 and 132001 come from the request itself and need a fix, not a retry.
How many times should an API call be retried?+
Usually three to five attempts, inside an overall deadline. The deadline matters more than the count: an OTP is worthless after a minute, while a delivery update can wait an hour.
What is the difference between a retry policy and exponential backoff?+
The retry policy decides whether and how often to retry; exponential backoff decides how long to wait between attempts. A good policy uses backoff with jitter, but backoff alone does not stop you retrying errors that can never succeed.
What is a retry budget?+
A retry budget limits retries to a share of total requests, often 10%. When failures exceed it the client stops retrying and fails fast, so retries cannot overwhelm a service that is already struggling.
Is this the same as Meta's webhook retry policy?+
No. Meta's webhook retry policy is how Meta re-sends webhooks to your endpoint, for up to seven days. Your retry policy governs your own outbound calls, such as sending messages.

10 · Pro tips

Best practices for a retry policy

  • Keep the classification table in one shared module, with a unit test for every error code it names.
  • Log the attempt number and the chosen action on every failure, so dashboards separate retries from first attempts.
  • Treat unknown error codes as dead-letter, not retry, and review them weekly.
  • Revisit the table whenever Meta documents new Cloud API error codes.

See InfiQ pricing

From definition to your first message

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.