> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# WhatsApp 24h freeform window

> Meta's 24-hour customer-care window — what it allows, how to check it, and how the platform pre-flights every send.

# WhatsApp 24h freeform window

Meta's WhatsApp Business Platform splits outbound messages into two regimes:

1. **Inside the 24-hour customer-care window** — your business may send any allowed content type (text, media, interactive buttons, lists, location). Free-form replies and ad-hoc support flows live here.
2. **Outside the 24-hour window** — only **pre-approved templates** in one of Meta's four conversation categories (Marketing, Utility, Authentication, Service) may be sent.

The window opens (or re-opens) every time the customer sends an inbound message to your WABA phone number. From the timestamp of that inbound message you have 24 hours to send free-form replies; the next inbound message resets the clock.

This page covers how to check the window status pre-flight, the platform's send-time enforcement, and how the dashboard surfaces the rule.

## How the window opens / closes

| Event                                        | Effect on the window                                                        |
| -------------------------------------------- | --------------------------------------------------------------------------- |
| Customer sends a message to your WABA number | Window opens for 24 hours. Subsequent inbound messages reset the 24h clock. |
| You send a template message                  | Window does NOT open — only an inbound from the customer can do that.       |
| 24 hours elapse without a new inbound        | Window closes. Free-form sends will be rejected.                            |

The window is keyed on the `(customer_phone, your_whatsapp_business_phone_number)` pair. A customer who has messaged your `+1-800` number does NOT open the window for your `+44-7700` number.

## Check the window status pre-flight

The dashboard's compose dialog calls this endpoint as the operator types — the BE is the authoritative source, but the FE pre-flight avoids a wasted send-attempt round-trip.

```bash theme={null}
curl -G https://api.orbit.devotel.io/api/v1/messages/whatsapp/window-status \
  -H "X-API-Key: dv_live_sk_..." \
  --data-urlencode "to=+14155552671" \
  --data-urlencode "from=+18005551234"
```

`from` is optional. When supplied, the lookup is scoped to inbound from `to` directed at the specific `from` number — matches the per-WABA scoping the send route enforces. When omitted, any inbound from `to` to any of your WABA numbers counts.

### Response

```json theme={null}
{
  "data": {
    "within_window": true,
    "last_inbound_at": "2026-05-09T08:42:11Z",
    "hours_since_last_inbound": 4,
    "reason": "within_window"
  },
  "meta": { "request_id": "req_xyz789", "timestamp": "2026-05-09T12:42:11Z" }
}
```

### `reason` values

| Value                | Meaning                                                                                                        |
| -------------------- | -------------------------------------------------------------------------------------------------------------- |
| `within_window`      | The contact has messaged you within the last 24 hours; free-form sends are allowed.                            |
| `window_expired`     | The contact has messaged you in the past, but the most recent inbound is older than 24 hours. Send a template. |
| `no_inbound_history` | We have no inbound history for this `(to, from)` pair. Templates only.                                         |

## Send-time enforcement

The send route (`POST /api/v1/messages/whatsapp`) re-runs the window check server-side and refuses free-form sends that would break Meta's rule:

```http theme={null}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "WHATSAPP_OUTSIDE_24H_WINDOW",
    "message": "The 24-hour customer-care window has expired. Use a template or wait for the customer to message first."
  }
}
```

Template sends (`type=template`) bypass the window check — they are always permitted, subject to the template's own approval status and category.

## Dashboard signals

In the inbox conversation header and the WhatsApp compose dialog the dashboard renders one of four states:

| State                        | Compose behaviour                                                |
| ---------------------------- | ---------------------------------------------------------------- |
| Window open, > 1h remaining  | Free-form composer enabled; subtle "open until {time}" badge.    |
| Window open, \< 1h remaining | Free-form composer enabled; orange countdown.                    |
| Window closed                | Free-form composer disabled; template picker is the only option. |
| No history                   | Free-form composer disabled; template picker required.           |

The countdown ticks once per minute via the dashboard's shared 1Hz tick — no per-row clocks.

## Templates approved for outside-window use

Templates are categorised by Meta when you submit for approval:

| Category         | Use case                        | Example                                                                         |
| ---------------- | ------------------------------- | ------------------------------------------------------------------------------- |
| `MARKETING`      | Promotional / campaign content. | "Spring sale — 20% off all stock until Sunday."                                 |
| `UTILITY`        | Transactional updates.          | `"Your order ORD-12345 has shipped — track it here: {{1}}"`                     |
| `AUTHENTICATION` | OTP / 2FA codes.                | `"Your verification code is {{1}}."`                                            |
| `SERVICE`        | Customer service responses.     | `"Hi {{1}}, our team is reviewing your case and will respond within 24 hours."` |

Pricing varies by category — see the [WhatsApp pricing guide](/guides/whatsapp/pricing).

## Common patterns

### Re-engagement template

If you regularly need to reach customers outside the window, build an approved Marketing or Utility template that re-opens the conversation:

```bash theme={null}
# Step 1: send the template (allowed outside the window)
curl -X POST https://api.orbit.devotel.io/api/v1/messages/whatsapp \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+14155552671",
    "type": "template",
    "template": {
      "name": "back_in_stock",
      "language": { "code": "en" },
      "components": [{ "type": "body", "parameters": [{ "type": "text", "text": "Air Max 90" }] }]
    }
  }'

# Step 2: customer replies → window opens → you can send free-form
```

### Branching on window status

```typescript theme={null}
import { Devotel } from "@devotel/orbit-sdk";

const orbit = new Devotel({ apiKey: process.env.ORBIT_API_KEY! });

const status = await orbit.messages.whatsappWindowStatus({
  to: "+14155552671",
  from: "+18005551234",
});

if (status.data.within_window) {
  await orbit.messages.sendWhatsApp({
    to: "+14155552671",
    from: "+18005551234",
    type: "text",
    text: { body: "Thanks for your patience — your order shipped today!" },
  });
} else {
  await orbit.messages.sendWhatsApp({
    to: "+14155552671",
    from: "+18005551234",
    type: "template",
    template: {
      name: "order_shipped",
      language: { code: "en" },
      components: [{ type: "body", parameters: [{ type: "text", text: "ORD-12345" }] }],
    },
  });
}
```

## See also

* [Channels → WhatsApp](/channels/whatsapp) — capabilities, media types.
* [WhatsApp pricing](/guides/whatsapp/pricing) — per-category template costs.
* [WhatsApp Business Calling](/guides/whatsapp/business-calling) — calls follow a separate permission state, not the 24h window.
