24-Hour Messaging Window
WhatsApp Business API enforces a 24-hour customer service window that determines what types of messages you can send. Understanding this rule is essential for building reliable WhatsApp integrations.
How It Works
The 24-hour window opens when a customer sends you a message. During this window, you can send any message type without a template. When the window closes, you can only send pre-approved template messages.
Customer sends a message
|
v
24-hour window OPENS
|
|-- You can send: text, media, interactive, reactions, etc.
|
24 hours later...
|
v
24-hour window CLOSES
|
|-- You can ONLY send: approved template messages
Rules at a Glance
| Window Status | Allowed Messages | How to Send |
|---|---|---|
| Open (customer messaged within 24h) | All types: text, media, interactive, reactions | POST /api/v1/messages |
| Closed (no customer message in 24h) | Template messages only | POST /api/v1/whatsapp-templates/{id}/send |
What Reopens the Window
The 24-hour window restarts (resets to a full 24 hours) every time a customer sends you a message. This includes:
- Text messages
- Media messages (images, documents, audio, video)
- Button/list reply selections
- Reactions
Messages from your side (outbound) do not reopen the window. Only inbound messages from the customer reset the timer.
Handling the Window in Your Integration
Strategy 1: Respond to Inbound Messages
The simplest approach. When you receive a message.received webhook event, the window is guaranteed to be open:
# Webhook handler -- window is open
def handle_message_received(event):
conversation_id = event["data"]["conversation_id"]
# Safe to send any message type (reply to the existing conversation)
requests.post(
f"{BASE_URL}/messages",
headers=HEADERS,
json={
"conversation_id": conversation_id,
"text": "Thanks for reaching out! How can I help?",
"message_type": "text",
},
)
The text-message body field is text (a top-level string). There is no content wrapper — sending nested content is silently ignored.
Strategy 2: Use Templates for Outbound Initiation
When you need to reach out to a customer proactively (order updates, reminders, notifications), always use a template:
# Proactive outreach -- always use a template
def send_order_update(contact_id, order_id, delivery_date):
requests.post(
f"{BASE_URL}/whatsapp-templates/tpl_order_update/send",
headers=HEADERS,
json={
"contact_id": contact_id,
# Positional template: ordered list fills {{1}}, {{2}}, ...
# (For a NAMED template, pass a dict keyed by parameter name instead.)
"variable_values": [order_id, delivery_date],
},
)
Strategy 3: Graceful Fallback
Try sending a free-form message first. If it fails because the window is closed, fall back to a template:
def send_message_with_fallback(contact_id, channel_id, text, template_id, template_vars):
# Try free-form message first
response = requests.post(
f"{BASE_URL}/messages",
headers=HEADERS,
json={
"contact_id": contact_id,
"channel_id": channel_id,
"text": text,
"message_type": "text",
},
)
if response.status_code == 422:
# Window closed -- fall back to template
response = requests.post(
f"{BASE_URL}/whatsapp-templates/{template_id}/send",
headers=HEADERS,
json={
"contact_id": contact_id,
# template_vars: list (positional) or dict (named/numeric keys)
"variable_values": template_vars,
},
)
return response.json()
Do not rely on the fallback strategy for time-sensitive notifications. If the window is closed, the initial request fails and you lose time on the retry. For proactive messaging, always start with a template.
Common Scenarios
| Scenario | Window Status | Recommended Approach |
|---|---|---|
| Customer asks a question | Open | Reply with text, media, or interactive message |
| Customer taps a button reply | Open (refreshed) | Continue the conversation freely |
| Sending order confirmation | Unknown | Use a template message |
| Following up after 2 days | Closed | Use a template message |
| Sending a marketing promotion | Closed | Use a MARKETING template |
| Sending an OTP code | Unknown | Use an AUTHENTICATION template |
Error When Window Is Closed
If you send a non-template message with POST /api/v1/messages outside the window, nothing is sent and you receive 400:
{
"detail": {
"error": "WHATSAPP_WINDOW_EXPIRED",
"message": "WhatsApp 24-hour messaging window has expired. Please use a template message to re-engage this contact."
}
}
The same applies to conversations that started from a Click-to-WhatsApp ad: a free entry point window only waives Meta's fees and does not extend the time for free-form messages (see Pricing Inside the Window). If the contact has never written to you, error is WHATSAPP_NO_CUSTOMER_MESSAGE. Branch on detail.error, not on the message text.
The free-form rich-message endpoints (/messages/send/interactive, /send/contacts, /send/sticker) run the same check and return the same 400 errors, before anything is sent. /messages/send/carousel is not checked: a WhatsApp carousel is an approved template, which may be sent outside the window.
Pricing Inside the Window
An open window does not mean the message is free. Meta charges per delivered message. Each WhatsApp number gets 1,000 free service messages (free-form, non-template replies inside the 24-hour window) per month; the allowance resets monthly and does not roll over. From the 1,001st service message in a month, Meta charges each one at the utility rate for the recipient's country, set by Meta. Since October 1, 2026, utility templates sent inside the open window are charged as well. Replies inside a free entry point window and inbound messages stay free of Meta fees. The window opens when you reply within 24 hours to a user who wrote in from a Click-to-WhatsApp ad, and it can stay open for up to 7 days. Only ads opened in the WhatsApp app on Android or iOS open it. Meta Business Agent messages are still charged. Meta bills these fees directly through your WhatsApp Business Account; they are not on your SendSeven invoice.
Next Steps
- Send a Template Message -- sending templates with variables
- Understanding Templates -- template categories and structure
- Meta Template Library -- get an approved template in one call when the window has closed
- Getting Started with WhatsApp -- WhatsApp integration overview