Troubleshooting: WhatsApp 24-hour session expired
A WhatsApp free-form send is refused withWHATSAPP_SESSION_EXPIRED when
Meta’s 24-hour customer-service window for the recipient has closed. The
window opens when the recipient messages you and stays open for 24 hours
after their last inbound message; outside it, WhatsApp accepts template
messages only — any session (free-form) send is refused either by Orbit
before dispatch or by Meta further down the same chain
(WHATSAPP_RE_ENGAGEMENT_WINDOW_CLOSED / WHATSAPP_RE_ENGAGEMENT_REQUIRED,
then WHATSAPP_OUTSIDE_24H_WINDOW). The full window model is in the
24-hour window guide; this page is the fix
runbook for the error row you hit.
The gate is Meta-side and tenant-owned: it clears when the recipient
replies (a reply re-opens the window) or when you send an approved
template. Retrying the same free-form body changes nothing — pick the
remediation below instead. The code family sits in the
Error Code Reference.
What the rejection looks like
The refusal comes back on the send call with the code on the error envelope, and the same shape appears on failed rows in the Delivery Log, on campaign recipient failures, and onmessage.failed webhook
payloads:
retry_after in seconds the way
RATE_LIMITED carries one. No amount of waiting with the same free-form
body re-opens the window — only a recipient reply re-opens it. Time
helps exactly one way: waiting for the recipient to answer. Until then,
template messaging is the only path through. How re-engagement works is
the subject of the
24-hour window guide.
Root causes
The window-status endpoint and its
reason values (within_window,
window_expired, no_inbound_history, unknown) are documented on the
WhatsApp channel page.
Fixes
1. Gate the UI with the window-status check
Before you let an agent or integration compose a free-form message, check whether the recipient is still inside the window:within_window: false, switch the composer to
template-only instead of letting the send fail. The send pipeline
enforces the same check at dispatch; the pre-flight exists so the UI can
prevent the wasted attempt.
2. Fall back to an approved template
Outside the window, the only permissible content is an approved template. Resend the substantive content as a template message, then treat the recipient’s reply as the trigger to resume free-form:3. Re-engage the recipient
Once the recipient replies to anything — a template, an earlier free-form message, even a reaction — the window re-opens and free-form is accepted again. Structure re-engagement templates so a reply comes naturally, and time follow-ups inside the window rather than batching them hours later.What not to do
- Do not retry the free-form send in a tight loop. Every retry fails identically until the recipient replies — the error is deterministic, not transient, and the retry storm only pollutes your delivery metrics.
- Do not treat this as a rate limit. Backing off for a few seconds
and resending is the wrong tool; there is no cooldown to wait out.
Re-route: send a template, or move the content to a different channel
with a cascade (SMS or Email under one
message_group_id— see Cascade failover policy). - Do not send the same content on every channel at once. Cascade fallback is ordered and conditional; a blast on every channel is spam the recipient can report, which degrades your WABA quality rating.
Escalation criteria
Open a ticket with support@devotel.io when the window-status pre-flight reportswithin_window: true and the
free-form send is still refused with this code, or when refusals persist
across every recipient rather than the lapsed ones. Include:
- The
request_idfrommetaon the refusal. - The
toandfrompair exactly as sent. - The window-status response (endpoint output above) showing the mismatch.
See also
- 24-hour window guide — the window model and re-engagement rules
- WhatsApp channel page — window-status endpoint, templates, media, broadcast
- Template variant missing — when the fallback has no WhatsApp variant
- WhatsApp template troubleshooting — rejected, paused, or count-mismatched templates
- Error Code Reference — the full
WHATSAPP_SESSION_EXPIRED/ re-engagement code family - Troubleshooting hub — every runbook in one index