Nurture TechnologiesNurture Tech
Integrations14 min·July 24, 2026

WhatsApp Business API Messages Not Delivering

WhatsApp Cloud APIMeta Business SuiteNode.jsWebhook

Your API calls return 200 OK but recipients never see the messages. Walk through every layer number verification, template approval, session windows, quality ratings, opt-outs, and rate limits to find exactly which gate is closed.

Problem Summary

You call the WhatsApp Cloud API, receive a 200 OK response with a message ID, but the recipient's phone never shows the message. The failure is silent no error in your response, but the message simply does not arrive. This is one of the most frustrating integration problems because the API accepted the request; the failure lives downstream in Meta's delivery pipeline or in the account configuration.

Symptoms

  • API returns HTTP 200 with a valid message ID but recipient sees nothing
  • Message status webhook never fires 'delivered' or 'read' stays at 'sent' indefinitely
  • Only specific recipients fail while others in the same batch succeed
  • Template messages fail with error code 131026 or 131047
  • Freeform text messages fail outside of the 24-hour customer-service window
  • All messages stop delivering after a certain time each day then resume the next day
  • Newly onboarded phone number delivers zero messages despite correct API calls
  • Users who previously received messages suddenly stop receiving them

Business Impact

WhatsApp is frequently a primary customer communication channel for transactional notifications OTP codes, order confirmations, appointment reminders. Silent message failure breaks trust immediately: customers think the service is down, support tickets spike, and time-sensitive messages like OTPs expire before they can be resent. For marketing campaigns, a failed send wastes the entire audience budget for that run.

Root Cause

WhatsApp Business API message delivery has seven independent gates, any one of which can silently swallow a message. Unlike email, there is no bounce notification in real time you only know through the webhook status callbacks, and many teams do not monitor those carefully. The most common culprits are: the phone number not being verified for the correct business account, the message template not having Meta approval, attempting a non-template message outside the 24-hour session window, quality rating falling below the threshold that allows sending, recipients who have opted out, and the daily business-initiated messaging limit being reached.

A 200 OK from the Cloud API only means Meta accepted the request for processing. It does not guarantee delivery. Always monitor the 'messages' webhook for status updates of 'sent', 'delivered', 'read', and 'failed'.

Diagnosis

Step 1 Verify the Phone Number Is Registered and Approved

The phone number must be added to your WhatsApp Business Account (WABA), verified via the OTP flow, and have its display name approved by Meta before any message can leave the platform.

$curl -X GET 'https://graph.facebook.com/v20.0/<PHONE_NUMBER_ID>?fields=verified_name,code_verification_status,quality_rating,status&access_token=<TOKEN>'

Look for: code_verification_status = VERIFIED, status = CONNECTED, quality_rating = GREEN or YELLOW. Any other value and delivery will fail or be throttled.

In Meta Business Suite go to: Business Settings → WhatsApp Accounts → [Your WABA] → Phone Numbers. A yellow warning triangle means the number has a pending action.

Step 2 Check Template Approval Status

Template messages (the only type allowed outside an active session) must be in APPROVED status. PENDING, REJECTED, or PAUSED templates will silently fail or return a 131026 error.

$curl -X GET 'https://graph.facebook.com/v20.0/<WABA_ID>/message_templates?fields=name,status,category,language&access_token=<TOKEN>'

If a template is PAUSED it means it received too many negative signals (blocks/reports). You cannot resume it until Meta's review. If REJECTED, review the rejection reason in the response's 'rejected_reason' field and revise accordingly.

template-status-response.json
{
  "data": [
    {
      "name": "order_confirmation",
      "status": "PAUSED",
      "category": "TRANSACTIONAL",
      "language": "en_US",
      "rejected_reason": "NONE",
      "id": "1234567890"
    }
  ]
}

Step 3 Validate the 24-Hour Customer-Service Window

Non-template (freeform) messages can only be sent within 24 hours of the most recent inbound message from that recipient. Sending outside this window returns error 131047: 'Re-engagement message'. The window resets each time the customer sends you a message.

check-session-window.ts
// Track the last inbound message timestamp per recipient
function canSendFreeformMessage(lastInboundAt: Date): boolean {
  const windowMs = 24 * 60 * 60 * 1000; // 24 hours
  const elapsed = Date.now() - lastInboundAt.getTime();
  return elapsed < windowMs;
}

// If outside window, you MUST use an approved template
async function sendMessage(to: string, lastInboundAt: Date | null) {
  if (!lastInboundAt || !canSendFreeformMessage(lastInboundAt)) {
    return sendTemplateMessage(to, "re_engagement_template");
  }
  return sendFreeformMessage(to, "Your reply here");
}

Step 4 Check Quality Rating and Messaging Limits

WhatsApp imposes tiered daily limits based on quality rating. Tier 1 allows 1,000 unique recipients per day; Tier 2: 10,000; Tier 3: 100,000; unlimited tier requires sustained good quality. When you hit the limit, subsequent messages queue and may be dropped.

$curl -X GET 'https://graph.facebook.com/v20.0/<WABA_ID>?fields=on_behalf_of_business_info,message_template_namespace&access_token=<TOKEN>'

Navigate to Meta Business Suite → WhatsApp Manager → Insights → Messaging Limits to see your current tier and how many messages you have sent today against your cap.

Step 5 Audit Opt-Out Status and Business Verification

If a recipient replied STOP or blocked your number, the API will still accept the message but Meta will not deliver it. There is no API endpoint to query opt-out status you must track this from incoming webhooks. Additionally, your Meta Business Account must be verified (not just the phone number) for higher-volume sending.

track-optouts.ts
// In your webhook handler, track opt-out signals
app.post("/webhook", (req, res) => {
  const entry = req.body.entry?.[0];
  const changes = entry?.changes?.[0]?.value;

  // Inbound message  if user said STOP, mark them opted out
  const messages = changes?.messages ?? [];
  for (const msg of messages) {
    if (msg.type === "text") {
      const text = msg.text.body.trim().toUpperCase();
      if (["STOP", "UNSUBSCRIBE", "CANCEL"].includes(text)) {
        db.markOptedOut(msg.from); // your persistence layer
      }
    }
  }

  // Check statuses for failed deliveries
  const statuses = changes?.statuses ?? [];
  for (const status of statuses) {
    if (status.status === "failed") {
      console.error("Delivery failed", {
        to: status.recipient_id,
        errorCode: status.errors?.[0]?.code,
        errorTitle: status.errors?.[0]?.title,
      });
    }
  }

  res.sendStatus(200);
});

Production Failure Scenarios

Scenario 1 OTP Messages Failing for New Users

Your AUTHENTICATION template must use the dedicated AUTHENTICATION category, not UTILITY. Meta restricts OTP templates heavily. If you created an OTP template under the wrong category it will not qualify for the higher delivery priority and may be rate-limited aggressively during peak hours.

Scenario 2 Campaign Blast Stops Partway Through

You send 5,000 messages in a loop but only 1,000 arrive. You have hit the daily Tier 1 cap. The messages after the cap are not queued they are dropped. The API still returns 200 OK for each. You must implement your own rate-limited queue that respects the daily ceiling and resumes the next UTC day.

Scenario 3 Messages Deliver to Some Countries But Not Others

WhatsApp has country-level restrictions for certain template categories. A MARKETING template approved for US phone numbers may not be deliverable to IN (India) numbers without additional review. Check your template's allowed_countries list if delivery is selectively failing by region.

Scenario 4 Delivery Stops After Number Quality Drops to RED

Once quality rating hits RED, Meta immediately disables outbound template messages from that number. You cannot send anything not even transactional alerts until the rating recovers to YELLOW over a 7-day rolling window. This is a full service outage for that phone number.

Prevention Checklist

  • Monitor message status webhooks and alert on any 'failed' status with error codes 131026, 131047, 131048, or 131056
  • Keep a local opt-out registry updated from inbound STOP messages never re-send to opted-out numbers
  • Throttle bulk sends to stay 20% below your current daily tier limit to leave headroom
  • Use the AUTHENTICATION template category for OTP flows, not UTILITY or MARKETING
  • Review template content with Meta's policy before submission no all-caps, no misleading CTAs
  • Implement exponential backoff and a dead-letter queue for messages that return 429 or 500 errors
  • Set up a daily cron job to query phone number quality rating and alert if it drops to YELLOW
  • Ensure your webhook endpoint returns 200 within 20 seconds or Meta will retry and may flag your endpoint
  • Test with a sandbox number in the Meta Developer Console before using your production WABA
  • Document and enforce the opt-in mechanism only send to users who explicitly requested messages

Resolution Summary

Work through the gates in order: verify the phone number is connected and verified, confirm the template is in APPROVED status, check that you are within the 24-hour session window for freeform messages, validate your daily send count against your tier limit, and ensure the recipient has not opted out. In most cases the issue is one of the first three. Fix the gate that is closed and delivery resumes immediately for new messages.

Lessons Learned

  • A 200 OK from the Cloud API is not delivery confirmation build your system around webhook status callbacks
  • Template approval can take 24-48 hours never submit a new template the night before a campaign launch
  • Quality rating degradation is almost always caused by sending to people who did not explicitly opt in
  • Daily messaging limits are a hard wall with no burst capability architect your queue with date-based pacing
  • Maintaining a local opt-out list is your responsibility; WhatsApp does not expose an API to query this

Conclusion

WhatsApp Business API delivery failures are almost always configuration or policy problems rather than code bugs. The API is designed to accept requests optimistically; the real enforcement happens in Meta's delivery layer. Build observability into your webhook handler first, then work backward through each delivery gate when you see failures. Once you have visibility into status callbacks, the root cause becomes obvious within minutes.

Nurture Technologies

NEED HELP WITH YOUR STACK?

Nurture Technologies builds and maintains production-quality software for startups and businesses. If engineering problems are slowing you down, our team can help.

Talk to our team →
FAQ

FREQUENTLY ASKED QUESTIONS

Why does the API return 200 OK but the message never arrives?+

The 200 OK only means Meta accepted the request into its pipeline. Delivery failures due to quality rating, opt-out, template issues, or daily limits are reported asynchronously through the messages webhook as a 'failed' status event.

How long does WhatsApp template approval take?+

Typically 24-48 hours for new templates. Templates in the MARKETING category sometimes take longer. If a template is stuck in PENDING for more than 48 hours, resubmit it or contact Meta Business Support.

What is the 24-hour messaging window exactly?+

It is a 24-hour window that opens each time a customer sends your business any message on WhatsApp. Within this window you can send freeform (non-template) messages. Outside it, you must use an approved template.

Can I check if a user has opted out via the API?+

No. WhatsApp does not expose an opt-out query endpoint. You must track opt-outs yourself by listening for inbound messages containing STOP, UNSUBSCRIBE, or similar keywords, and from 'failed' webhook events with error code 131026.

What error code means I hit the daily messaging limit?+

Error code 131056 (too many requests) or 130429 (rate limit hit) indicates you have reached your daily business-initiated messaging tier. Check Meta Business Suite → WhatsApp Manager → Insights for your current usage.

How do I increase my daily messaging tier?+

Maintain a GREEN quality rating for 7 consecutive days and your tier increases automatically by one level (1K → 10K → 100K → unlimited). There is no manual escalation path quality and consistency are the only levers.

My quality rating dropped to RED. What do I do?+

Immediately pause all bulk/marketing sends. Only send critical transactional messages to users who explicitly requested them. The rating recovers on a 7-day rolling window as the block/report rate falls. Do not try to send more messages to 'dilute' the bad signals it makes it worse.

Why is my AUTHENTICATION template being rejected?+

Common reasons: using the UTILITY category instead of AUTHENTICATION, including marketing content in the template body, having a CTA that is not an OTP copy button, or the template not including the required security disclaimer.

Do I need to reverify my phone number periodically?+

No, phone number verification is a one-time step. However, if you transfer the number to a different WABA or Meta Business Account, you must re-verify. The display name reapproval may also be required after certain account changes.

Can I send WhatsApp messages to numbers not on WhatsApp?+

No. The API silently drops messages to non-WhatsApp numbers in most cases, or returns a 'failed' webhook status. There is no pre-check endpoint you can only discover this from the delivery webhook.