DEV Community

Ramdai Bista
Ramdai Bista

Posted on Originally published at agentkitworks.com

Why Retrying a Failed WhatsApp Send Is the Dangerous Move, Not the Safe One

If you're wiring an agent to send WhatsApp messages, there are two rules that aren't optional, and one instinct you have to actively suppress. The instinct is the one that gets people in trouble: retry on failure.

There's no direct route — only Business API providers

You can't automate the consumer WhatsApp app. Every path runs through a Meta-approved WhatsApp Business API provider (Wati, Twilio, 360dialog, and a handful of others all sit on the same underlying rules). That's not a vendor preference — it's the only door Meta built.

Two rules apply no matter which provider you pick:

  1. A business-initiated message needs a pre-approved template. You can't just fire off free text to someone who hasn't messaged you first. Meta requires a template that's been reviewed and approved ahead of time for anything outside a customer-opened 24-hour window.
  2. Free-text replies only work inside that 24-hour window. Once a customer messages you, you get 24 hours to reply with whatever you want. Miss the window, and you're back to templates only.

Neither of these is where people actually get burned, though.

The real failure mode: retrying after a timeout

Here's the one that costs you: a request to send a message times out. What do you do?

The instinctive answer — retry, because a timeout probably means it failed — is wrong, and it's wrong in a way that's specific to this kind of channel. A timeout doesn't tell you the send failed. It tells you the response never arrived. The message may well have gone through; you just didn't hear back in time.

If your retry logic treats any non-200 or any timeout as "didn't happen, try again," you will eventually double-send. On email, a duplicate is mildly annoying. On WhatsApp — a channel people read in real time, often with notifications on — a duplicate reads as broken, or worse, as spam. It's the kind of bug that doesn't show up in your logs as an error. It shows up as a customer complaint.

The fix is to treat a timeout as "unknown," not "failed," and resolve the unknown before you act on it:

  • After a timeout, check the message's delivery status via the API before deciding whether to resend.
  • Only retry once you've confirmed the original send did not go through.
  • If the provider gives you an idempotency key or client-generated message ID, use it — it lets the API itself dedupe a retry you send in good faith.

This is a general lesson that goes beyond WhatsApp: any at-least-once delivery system (webhooks, queues, payment APIs) has the same shape of bug. WhatsApp just makes the failure mode visible faster, because the recipient sees it instantly.

The other thing worth knowing before you build this: pricing is changing

Meta is introducing a new billed category starting October 1, 2026: free-text replies sent inside that 24-hour customer-service window will start counting as billed service messages — a cost bucket that doesn't exist today. If you're building an automated flow that leans on free-text replies at volume, price this in now. A cost model built before that date won't hold after it. Check current pricing from your provider directly before committing to a high-volume design.

The short version

  • No direct route — go through a Business API provider.
  • Templates for anything business-initiated; free text only inside the 24-hour window a customer opens.
  • A timeout means "unknown," never "failed" — check delivery status before you ever consider a resend.
  • Meta's billing for free-text service-window replies changes October 1, 2026 — model it before you scale.

Top comments (0)