The 24-hour window
It's the rule that confuses newcomers to official WhatsApp the most, and the most common
cause of 422 meta_error in production.
You can only send free-form messages within 24 hours of the customer's last message to you. Outside that window, WhatsApp accepts only previously approved templates.
How the window opens and closes
Only the customer's message opens the window. Your own messages don't extend it — sending ten in a row buys no extra time.
The error when the window is closed
{
"error": {
"message": "The Meta Cloud API rejected the request.",
"type": "meta_error",
"meta": {
"error": {
"message": "(#131047) Re-engagement message",
"code": 131047,
"error_subcode": 2494010,
"fbtrace_id": "AbCdEfGhIjK"
}
}
}
}
Code 131047 is the tell. Retrying won't help — the fix is to send a template.
Tracking the window in your system
The API has no "is this window open?" endpoint. You track it from the webhooks: every
incoming message carries a Unix timestamp.
// On receiving a `messages` webhook with a customer message:
const openUntil = Number(message.timestamp) * 1000 + 24 * 60 * 60 * 1000;
await db.conversations.upsert({ waId: message.from, windowOpenUntil: new Date(openUntil) });
// Before sending:
const conversation = await db.conversations.find({ waId: recipient });
const canSendFreeForm = conversation && conversation.windowOpenUntil > new Date();
Leave a few minutes of margin: the clock that counts is Meta's, not yours.
A practical strategy
Inside the window — use whatever you like: text, media, buttons, lists. It's cheaper and needs no approval.
Outside the window — send a template. It reopens the conversation; as soon as the customer replies, you're back to free-form content.
When in doubt — send the template. A message that arrives costs less than an error that doesn't.
Templates worth keeping approved
A small approved library keeps you from being held hostage by approval times:
| Situation | Category |
|---|---|
| Reviving a stalled conversation | UTILITY |
| Confirming an order, delivery or appointment | UTILITY |
| Sending a verification code | AUTHENTICATION |
| Announcing a promotion | MARKETING |
Creation details and variable rules are in Templates.
Cost
Meta bills per conversation, not per message. A conversation opened by a MARKETING
template costs more than a UTILITY one, and customer-initiated conversations
(SERVICE) are the cheapest — often free.
That changes how you design the integration: a flow that gets the customer to write first is cheaper than one that fires marketing templates.