Skip to main content

Troubleshooting: WhatsApp Flows API — 502 META_API_ERROR

The Flows list (GET /api/v1/whatsapp/flows) and Flows create endpoints proxy Meta’s Graph API. When Meta’s side of the call fails, Orbit returns a deliberately mapped error rather than passing Meta’s raw body through — so a 502 on these endpoints is not a raw upstream crash, it is a classified envelope you can decode. This page covers that envelope. If the problem is a Flow’s runtime (screen render, encrypted exchange) work Flow execution failures instead; if the WABA itself is disconnected, work Troubleshoot a WhatsApp connection.
The reconnect, publish-state, and token-recovery levers this page points at are all tenant-owned — Orbit’s role is to classify the upstream response so you know which lever to pull.

Symptom map

Work the table top-down — it covers the failure modes that account for nearly every 502 on the Flows endpoints.

Decode the META_API_ERROR variants

A 502 with code: "META_API_ERROR" bundles different upstream failures behind one code. The Messenger channel page uses the same pattern for its MESSAGE_SEND_FAILED 502 — read details.provider_message first, then pick the fix. Here the discriminator is details.isRateLimited: The dashboard Flows tab already stops auto-retrying when details.isRateLimited: true — if you built your own poller against the list endpoint, apply the same gate or you will burn the WABA’s call budget.

Test whether the failure is retryable

Run this decision in order — the first branch that matches is the answer:
  1. details.isRateLimited: true. Do not retry in a loop. Wait for Meta’s call-budget window to reset (a few minutes), then send one retry. Every extra request while throttled extends the window.
  2. Code META_API_ERROR, no rate-limit tag. Retryable. Send the retry with an Idempotency-Key header so a create call cannot double-create a Flow, and add jitter (a random 0–30 seconds on top of your backoff) so a fleet of pollers does not retry in lockstep.
  3. Code WHATSAPP_CONNECTION_INVALID or WHATSAPP_TOKEN_EXPIRED. Not retryable — the connection or token is deterministic-broken, so a retry returns the same thing. Reconnect from Settings → Channels → WhatsApp and retry only after the reconnect reports Connected.
  4. A 4xx body-validation error on the create endpoint with none of the codes above. Not retryable until the request body is fixed — re-check the Flow JSON field-by-field before resubmitting.

Rate-batching guidance

The throttled-WABA variant is nearly always self-inflicted — the Flows list endpoint is cheap to call in a loop, and Meta counts that loop against the WABA’s call budget. Keep the budget intact:
  • Poll the list endpoint on a schedule (minutes, not seconds) from server-side jobs, never from a re-render loop in a client.
  • Page with offset instead of re-requesting the whole list — each page call also counts against the budget.
  • When you are creating Flows in bulk, serialize the creates with a small delay rather than firing them concurrently.
  • If a campaign the Flows tab drives needs frequent refresh, throttle the refresh on details.isRateLimited rather than on a fixed timer.

Escalation payload

If you have worked the page and the same 502 persists across a WABA that is not throttled, email whatsapp-support@devotel.io with these three items so we can trace the upstream call without a back-and-forth:
  1. The request id from the response headers of a failing call.
  2. The variant branch — isRateLimited true vs absent, and the exact code and message you received.
  3. Whether the same request has succeeded before — a Flows list that never succeeds is a different trace than one that broke recently.

What not to do

  • Do not retry on a throttled WABA. details.isRateLimited: true is the signal to stop; every further request extends the window.
  • Do not reconnect on a 502 META_API_ERROR. Only WHATSAPP_CONNECTION_INVALID or WHATSAPP_TOKEN_EXPIRED resolves with a reconnect; reconnecting on a plain transient blip changes nothing.
  • Do not reuse an Idempotency-Key with a different body. Key reuse with a different payload is rejected; regenerate the key when the payload changes.

See also