Skip to main content

Troubleshooting: WhatsApp template pending, rejected, or blocked by the 24h window

A WhatsApp template problem shows up one of four ways: Meta’s review never finishes, the template comes back rejected, sends fail even on an approved template, or Meta reclassifies the template and your per-message price changes. This page covers the template layer only. If the phone number itself is stuck at a compliance gate, or a Sender ID is pending, that is a different flow — see Troubleshoot a pending number or Sender ID. If you are moving an existing WABA to Orbit, the WABA migration guide covers that path; this page assumes the WABA is already connected.
Template approval, quality scores, and category decisions are Meta’s call, not Orbit’s — Orbit submits, syncs the result, and enforces what comes back. Lead times in this page are expectations from current Meta behaviour, not guarantees.

Template sync fails with TEMPLATE_SYNC_FAILED (400)

POST /api/v1/whatsapp/templates/sync fails with a 400 whose error.code is TEMPLATE_SYNC_FAILED. This is a catalog-level failure: the sync call against the Meta Graph API was rejected before any template row was compared, so no individual template is at fault. The send-side gates this page covers elsewhere — TEMPLATE_NOT_APPROVED on a send, INVALID_TEMPLATE at render time — are per-variant verdicts on templates that already synced; a sync failure means the catalog itself never refreshed, and every per-template fix below assumes the sync already succeeded.

Cause family

The sync is Devotel-side against Meta Graph on behalf of your WABA, so the four causes it can fail on:
  • OAuth token expired or re-scoped. The stored Meta token from Embedded Sign-up lapsed, or Meta revoked a permission the sync needs before it can page the template list.
  • IP-allowlist mismatch on the tenant credential. If your WABA credential carries an allowlist in Meta’s app settings, Meta Graph rejects calls from addresses that are not on it.
  • WABA in a non-billable or locked state. An account under Meta enforcement, a missing payment method, or a disabled WABA refuses template reads before any template verdict applies.
  • Meta Graph transient 5xx. Meta’s own API had a bad moment; the rejection has your side in a healthy state.

Decision procedure

Work it top-down and retry the sync exactly once per fix:
  1. Re-check the connection state and brand quality. Read GET /api/v1/whatsapp/connections and confirm the WABA reports connected with no quality downgrade. A locked or restricted WABA fails every Meta Graph call, not just the sync — work Troubleshoot the WhatsApp connection first when the connection itself is red.
  2. Confirm the WABA credential set. Open Settings → Channels → WhatsApp and verify the stored credential still matches what Meta Business Manager shows for the WABA. If the OAuth grant expired or Meta re-scoped the permissions, re-run the connect flow from the same screen — the procedure and the token-family split are in WhatsApp re-authentication and Embedded Sign-up recovery.
  3. Retry the sync once after the cause is fixed. The sync is idempotent and safe to re-run, but never loop the same 400 — a deterministic rejection at Meta does not clear on repetition. If two consecutive fixed-and-retried attempts fail the same way, escalate with the payload at the bottom of this page.
If you are mid-migration, the same endpoint is Stage 4 of the move — the divergence classes (short sync, (name, language) mismatches on send) are in Troubleshoot WhatsApp migration stuck. This section covers only the sync call itself being refused; the endpoint contract is in WhatsApp templates API.

Symptom map

Work the table top-down — it covers the failure modes that make up nearly every template incident.

How to inspect a template

Every diagnostic on this page starts at the template record. Find it by the exact (name, language) pair from Meta Business Manager, then read it from Orbit:
The record carries the fields every check below reads. Fetch the full template detail at GET /api/v1/messages/templates/{id} for the complete body:
  • status — the local view of Meta’s verdict: pending_review, approved, rejected, paused, disabled, or submission_failed (Meta refused the create call itself — the request never became a template at their side).
  • metadata.rejection_reason — Meta’s own words for a rejection. This is the single most useful field on the page: it names the policy clause or formatting error Meta acted on.
  • external_id — Meta’s template id, present only after a successful submission. A missing external_id means the row has never been accepted by Meta.
For live updates, listen to the webhook events instead of polling: whatsapp.template.approved and whatsapp.template.rejected fire on Meta’s verdict (the rejected event carries details.reason), and whatsapp.template.quality_update fires on downgrades. The full event list and payload shape are in Webhook events. If you only watch the dashboard, the same events raise a bell notification naming the template.

Fix workflow per status

  • pending — let it run. Approval lands in minutes for utility and authentication templates. Marketing templates take longer. Do not resubmit while the first attempt is in flight — the two submissions compete for the same review slot.
  • rejected — edit and resubmit. Read metadata.rejection_reason, fix the named problem, and PATCH the template. Editing clears the way for resubmission, and Meta keeps the template name free for 30 days, so you do not need to rename. Reassign the category in the same edit if the rejection was a category mismatch.
  • submission_failed — fix the account, then resubmit. Meta refused the submission call: a WABA permission missing, the account under feature review, or an app-config problem. Nothing was created at Meta’s side, so the template body is usually fine. Verify the WABA state in Meta Business Manager, then resubmit.
  • Misclassified — resubmit with the category change. If a utility template kept coming back as marketing, its body reads as promotional. Rewrite the body so it only covers the order, booking, or account event, then resubmit as utility. Accepting marketing pricing is the cheaper fix when the content is genuinely promotional.
  • Sampling-limited — add a real opt-in example. When Meta asks for sample traffic, submit a screenshot or example from a real opted-in conversation rather than a fabricated one — a built-up example that never matched real traffic is one of the most common second-rejection causes.
  • Re-review window — wait. After a resubmission, a fresh review cycle starts. The status field and webhook events move again when Meta answers; the fix workflow from there is the same as for a new template.

What not to do

  • Do not spam POST /templates with the same body. Meta rate-limits duplicate submissions per WABA, and a rejected body resubmitted unchanged earns faster rejections. Every submission should fix what the rejection reason named.
  • Do not switch the category without adjusting the variables. A utility template that names a discount in {{1}} becomes a marketing template with the category flag flipped and nothing else changed — Meta’s reviewers catch that immediately, and so does the automatic reclassification later.
  • Do not reuse a rejected name immediately on a brand-new template. The 30-day name hold exists so the same name can be fixed in place. Deleting a rejected template and recreating it under the same name inside the hold window trips the duplicate-name throttle and delays the resubmission.
  • Do not test a rejected template with production traffic. A send against a non-approved template fails before it reaches Meta, and the failures count against your WABA’s quality metrics.

Escalation payload

If you have worked the page and the template is still stuck, email whatsapp-support@devotel.io with these three items so we can trace the review with Meta without a back-and-forth:
  1. Your WABA id (Meta Business Manager → WhatsApp Manager, or the waba_id on any template record).
  2. The template name + language exactly as Meta has them (order_shipped + en_US, not a display label).
  3. The rejection code or reason from metadata.rejection_reason, or the details.reason from the whatsapp.template.rejected webhook event.

See also

  • WhatsApp 24h freeform window — when a template send is required, the pre-flight window check, and the error codes that mean “send a template”.
  • WhatsApp content policy — the prohibited and restricted categories every rejection reason maps back to.
  • Templates API — the create/read/update contract for every endpoint this page uses.
  • Troubleshoot WhatsApp Flow submissions — the submissions/CDP layer playbook for Flow sends that went through.
  • WhatsApp Meta Policy Cadence — Meta-side enforcement shifts such as template-category migration, per-user marketing caps, and regional pause experiments.
  • Troubleshoot the WhatsApp connection — distinguish a locked WABA (WHATSAPP_ACCOUNT_LOCKED, Meta 131031 — account-level enforcement) from template-level failures: an account lock fails every send, including submissions.
  • WABA setup — first-time submission flow and the approval-timelines table.
  • Webhook events — the whatsapp.template.* events for driving this workflow from your own systems.