WhatsApp

What is the 24-hour customer service window on WhatsApp?

Two questions hide inside this one. What Meta's rule is, which is the same whichever provider you use, and what your provider does about it, which is not. The second is where the surprises live.

When does the window open and close?

The customer opens it. You never do.

Meta's own statement is that "When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window starts", and that "If the user messages or calls you again before the timer expires, the timer resets to 24 hours". An active back-and-forth therefore keeps the window open indefinitely, and a conversation that goes quiet closes it exactly 24 hours after the customer's last message or call.

While it is open you can send free-form content: text, images, documents and the other service message types Meta permits in a live conversation. None of it needs prior approval, because the customer started the exchange.

When it closes, Meta is blunt about what remains: "When the window closes, you can only send pre-approved template messages."

Nothing you send opens a window on its own terms. A template sent to someone who has not written to you starts the conversation from your side, and it still needs the opt-in Meta requires: "you can only send messages to WhatsApp users who have opted in to receiving messages from you". Meta also documents a known issue in which "In rare cases, you may receive a message from a WhatsApp user but be unable to respond within the customer service window."

Meta's full statement of the rule is on its send messages reference, and the WhatsApp customer service window covers the same ground with the Bird specifics beside it.

What happens when I send into a closed window?

One of two things, and the difference is who pays for the mistake.

The check catches it. Bird tracks the window and refuses a free-form send into a closed one at the moment you make the request. POST /v1/whatsapp/messages returns 422 with E15044, This conversation's 24-hour customer service window is closed, so only a template message can be sent. Nothing is created and nothing is charged. That is the entire point of checking beforehand: Meta only refuses the message after it has been sent, and by then it has been paid for.

The window closes underneath you. If it shuts between your request and dispatch, the message is created and then fails, carrying service_window_expired. Meta reports that closure as error 131047, or as the legacy 470, and both arrive as that one code.

The right response to E15044 is not a retry. It is to send an approved template instead, which reaches the contact now and reopens the window for free-form content as soon as they reply.

That holds even when the refusal looks wrong. If a send is refused for a contact you can see wrote to you inside the last 24 hours, sending the template still gets your message there, and it is worth contacting support with the message id.

Why did a send go out when the window was closed?

Because the check is deliberately permissive, and this is the part worth designing around.

The gate refuses a send only when it can positively determine the window is shut. Every other outcome admits the message. The case you are most likely to meet is the lookup failing: the send goes through, and the failure to decide is logged rather than surfaced to you. A group send arriving without the identifier the lookup needs is admitted on the same principle, as is a service with no window store behind it at all.

The reasoning is sound. Refusing on uncertainty would block real replies to customers who did write in, which is worse than paying for the occasional message Meta then rejects. But it makes the guarantee one-directional, and it is worth stating precisely: a refusal means the gate read a closed window, and an acceptance means only that it did not read a closed one. Neither is a promise about what Meta thinks the window is doing.

The two outcomes are not symmetric in cost, either. A caught send is refused before anything is created and costs nothing. An admitted one is charged at the going rate before dispatch, on a path with no refund behind it, and then comes back as a whatsapp.failed event carrying service_window_expired: the same closure, discovered later, and the money does not return. So a steady trickle of that code is not a reason to trust the pre-send check harder. It is a signal to send a template for anything that is not a prompt reply inside a live conversation.

Which content actually needs a template?

Anything that is not a reply inside an open window. Two-way WhatsApp is the shape that keeps one open.

That framing beats "marketing versus service", because the window does not care what the message says. It cares who spoke last, and when. A shipping update sent eleven hours after the customer's question is free-form content and goes straight through. The same update sent the next morning needs a template.

One Bird-specific constraint sits alongside the rule. Free-form content requires a number of your own, because Bird's shared numbers carry managed templates only. If you send from a shared number, everything you send is a template whatever the window is doing.

Sending WhatsApp messages covers both content kinds and what the 202 does and does not promise, and what a WhatsApp message template is covers the object you reach for whenever the window is shut.

How should I design around it?

Treat the clock as starting at the customer's message rather than at your team's.

For anything conversational this is a service-level constraint wearing a technical costume. If a question arrives at nine in the morning and a human picks it up the following afternoon, the reply cannot go out as an ordinary message at all, whatever the ticketing system thinks. Three things follow:

  1. Keep the last inbound timestamp per contact. You already receive it, and it is the only way to know how much window is left while you are composing the reply rather than after the API has refused it.
  2. Have a template ready for the overflow case. The useful one is not a marketing message but a short re-opener that invites a reply, because the reply is what restores free-form sending.
  3. Do not alert on E15044. It is the system working, and cheaply. What deserves an alert is a rising count of service_window_expired, because that is the check having failed to save you.

Build on the same network.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

एक चैनल से शुरुआत करें।
तैयार होने पर बाकी जोड़ें।

एक test API key तुरंत आपकी है। जब आप payment method जोड़ते हैं और sender verify करते हैं, तब production अनलॉक हो जाता है।

Claude Code, Cursor या Codex इस्तेमाल कर रहे हैं? एक setup prompt कॉपी करें और आपका agent आपके लिए Bird CLI और skills इंस्टॉल कर देगा। अपना चुनें:

Cursor