> ## 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 onboarding walkthrough

> Walk a complete first WhatsApp Business conversation on Orbit end to end — WABA connect, template approval, the first outbound send, the inbound reply, and the 24-hour window turn — with the exact request and webhook payloads at each step.

# WhatsApp onboarding walkthrough

This page walks one conversation from first touch to last turn. The [getting-started guide](/guides/whatsapp/getting-started) explains the platform rules; this walkthrough shows the actual requests, responses, and webhook events as a conversation flows, so you know exactly what your integration receives at each turn.

The conversation: a customer named Ada opts in at checkout, receives an order-confirmation template, replies with a question, and gets a free-form answer inside the 24-hour window.

## Before you begin

* A live Orbit API key (**Settings → API Keys**, prefix `dv_live_sk_`). Keep it server-side.
* A connected WhatsApp Business Account (WABA). The full connect path — Meta Business Manager, number verification, messaging tiers — is the [WABA setup guide](/guides/whatsapp/waba-setup).
* A webhook endpoint subscribed to the message events below. See [webhook security](/webhooks/security) for signature verification.

## Step 1 — Connect the WABA

In the dashboard: **Settings → Channels → WhatsApp → Connect**. Meta's embedded sign-up picks your Business Manager, creates or selects the WABA, and verifies your number. The channel shows **Connected** as soon as the number verifies — Meta's business verification can still be running in the background.

Until business verification completes, the WABA is capped at **250 unique recipients per 24 hours**. One onboarding-scale conversation costs nothing against that budget.

## Step 2 — Create and submit the template

Business-initiated messages must use an approved template. **Channels → WhatsApp → Templates → New Template**:

| Field | Value used in this walkthrough |
| - | - |
| Category | `utility` |
| Language | `en` (English) |
| Name | `order_confirmation` |
| Body | `Hi {{1}}, your order {{2}} confirmed — we're packing it now. Track it here: {{3}}` |

Approval is usually minutes; allow up to 24 hours. You can watch it from your own systems instead of polling — subscribe to the template events:

```json theme={null}
// webhook: whatsapp.template.approved
{
  "id": "evt_tpl_9f2c1",
  "type": "whatsapp.template.approved",
  "created_at": "2026-10-08T14:02:11Z",
  "data": {
    "template_name": "order_confirmation",
    "language": "en",
    "category": "utility"
  }
}
```

A rejection arrives as `whatsapp.template.rejected` with a `rejection_reason` field — the most common cause is a category mismatch (promotional copy filed as `utility`). See the [content policy](/compliance/whatsapp-content-policy).

## Step 3 — Send the first template message

Once approved, send:

```bash theme={null}
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": "order_confirmation",
      "language": { "code": "en" },
      "components": [
        {
          "type": "body",
          "parameters": [
            { "type": "text", "text": "Ada" },
            { "type": "text", "text": "ORD-12345" },
            { "type": "text", "text": "https://shop.example.com/track/ORD-12345" }
          ]
        }
      ]
    }
  }'
```

```json theme={null}
{
  "data": {
    "id": "msg_8d41f2",
    "channel": "whatsapp",
    "to": "+14155552671",
    "status": "queued"
  }
}
```

Persist the `id` — it is the key in every webhook event that follows this message.

## Step 4 — Watch the delivery progression kill your polling loop

Each message posts its lifecycle to your endpoint as it moves:

```json theme={null}
{ "type": "message.sent",      "data": { "message_id": "msg_8d41f2", "to": "+14155552671", "status": "sent" } }
{ "type": "message.delivered", "data": { "message_id": "msg_8d41f2", "to": "+14155552671", "status": "delivered" } }
{ "type": "message.read",      "data": { "message_id": "msg_8d41f2", "to": "+14155552671", "status": "read" } }
```

`sent` is Meta accepting the message; `delivered` is the device's receipt; `read` is the customer opening the chat. An undeliverable number produces `message.failed` with an `error.code` you can route on (for example `131030` recipient-not-allowed — the number is not opted in to your WABA).

## Step 5 — Receive the customer's reply

When Ada replies, you receive the inbound message as `message.received`:

```json theme={null}
{
  "id": "evt_in_53kdp",
  "type": "message.received",
  "created_at": "2026-10-08T14:11:47Z",
  "data": {
    "message_id": "msg_2c7a09",
    "from": "+14155552671",
    "channel": "whatsapp",
    "type": "text",
    "text": "Can I change the delivery address before it ships?"
  }
}
```

Her reply opens the 24-hour service window: from this moment you can send free-form messages without a template until the window closes. See [the 24-hour window](/guides/whatsapp/24h-window) for the full state model.

## Step 6 — Answer inside the window

Free-form sends look like template sends but drop the `template` object:

```bash theme={null}
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": "text",
    "text": { "body": "Yes — reply with the new address and we will update the shipment before it leaves the warehouse." }
  }'
```

Zero-cost per-message round trip: this is a service conversation, [priced differently from template sends](/guides/whatsapp/pricing).

## Step 7 — Check window status before composing free-form from a job

Batch jobs and campaign senders cannot assume a window is open. Pre-flight the check:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/messages/whatsapp/window-status?to=%2B14155552671&from=%2B18005551234" \
  -H "X-API-Key: dv_live_sk_..."
```

```json theme={null}
{ "data": { "window_open": false, "seconds_remaining": 0 } }
```

If you skip the check and send free-form outside the window, the send is rejected with a **422** — it is not silently dropped. For a closed window, send a re-engagement template instead; when the customer replies to it, a new window opens.

## Verify the wiring end to end

Run this checklist on a live WABA before you roll the integration to real customers:

* [ ] Template send returns `200` with a `msg_` id
* [ ] `message.sent` then `message.delivered` arrive on your webhook, same `message_id`
* [ ] Replying from a handset produces `message.received` within a second
* [ ] A free-form send during the open window returns `200`
* [ ] The window-status endpoint flips to `window_open: false` after 24 hours of silence
* [ ] Webhook signature verification passes on every event ([how](/webhooks/security))

## Frequently asked questions

### Do I need a real Meta Business Manager to test this?

Yes — but your own phone number on a verified WABA works as the test customer. The 250-recipient starter cap is far more than an onboarding test needs. There is no separate Meta sandbox on Orbit; test against the live platform with a small loop of numbers you control.

### A free-form send returned 422 — what did I miss?

Two common causes: the 24-hour window has closed (check with `window-status`), or the number has never messaged the WABA and no template is being used. Both resolve the same way — send an approved template, then continue free-form once the customer replies.

### Why did `message.read` never arrive?

Read receipts are the customer's choice — WhatsApp lets users disable them. Your integration must treat `message.delivered` as the success terminal state and `read` as informational.

### How do I run a second conversation lane while testing?

Multiple WABAs on one Orbit account are supported. Connect the second through **Settings → Channels → WhatsApp → Connect** and pick a different WABA in embedded sign-up. Each WABA routes events to the same workspace webhooks, distinguished by the `from` number in each event.

## Next steps

* [The 24-hour window](/guides/whatsapp/24h-window) — full state model, re-engagement rules, and edge cases.
* [Create and approve templates](/guides/whatsapp/templates-create-approve) — variables, buttons, and media headers.
* [WhatsApp channel reference](/channels/whatsapp) — every request field, including media and interactive messages.
* [API migration parity map](/guides/whatsapp/api-migration-parity) — moving an existing Meta Cloud API integration onto Orbit's shape.
* [Campaign launch playbook](/guides/whatsapp/campaign-launch-playbook) — when one walkthrough becomes a production send lane.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.