# WhatsApp in Connect

Connect receives WhatsApp messages on a workspace's own Meta business number and answers under the same autonomy rule that governs email and phone. The number is connected one of two ways — Official API, the business's own Meta app, or QR-linked, Meta's coexistence route through Embedded Signup. The number, template approval, the 24-hour window and delivery reporting belong to Meta; Connect works inside them.

- **Status:** Available
- **Audience:** both
- **Channels:** whatsapp
- **In the app:** #/whatsapp, #/whatsapp-setup
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/whatsapp/

## What the channel actually is

WhatsApp in Connect is `whatsapp.py` and `whatsapp_api.py`: an inbound webhook, a resolution chain that turns a phone number into a Person in your relationships, a canonical conversation the engine and the Conversations screen both read, and a send that goes to Meta's Graph API through `whatsapp.send_message` — or, when Connect is acting on its own, through `whatsapp.dispatch`, which asks the autonomy policy first.

Nothing about that chain is special to WhatsApp. A message arriving here becomes the same kind of record an email becomes, so the reply is drafted by the same agent loop, held or sent by the same autonomy rule, counted against the same allowance and written into the same relationship timeline. If you already know how a reply on email is decided, you know how a reply here is decided.

What is specific to WhatsApp is the etiquette Meta enforces from outside Connect: a business may not message a person freely, only inside the 24-hour window the person opened by writing first, or with a template Meta has approved. Those rules are not Connect's, and Connect does not pretend they are absent — the window is checked locally before the network call, because finding out from Meta instead costs a refused send.

## Two ways to connect one number

A workspace connects its number one of two ways, and `whatsapp.py` calls them `official` and `coexistence`. Both land in the same tables and pass the same window, consent, autonomy and metering checks, and `whatsapp_engine` does not know which one it is answering on.

| Mode | What it is | What is different |
|---|---|---|
| Official API | The business's own Meta app, token and number on the WhatsApp Business Platform | The primary route. Automatic sends are capped at 120 per number per hour. |
| QR-linked | Meta's own coexistence route through Embedded Signup: the business keeps using the WhatsApp Business app on the phone and scans a QR code | A warning is accepted word for word and audit-logged, the number carries a standing risk banner, and automatic sends are capped at 20 an hour. |

> **Careful** QR-linked is Meta's coexistence flow, not a scraped WhatsApp Web session. Connect implements no web automation, no device emulation and nothing else meant to get around Meta's controls. It also cannot open Meta's signup in production yet — [What WhatsApp cannot do here](/docs/whatsapp/whatsapp-limits/) says why.

## Who owns which part

| Concern | Owned by | What that means for you |
|---|---|---|
| The business number and display name | Meta | Changing either is done in Meta's own console, not in a Connect setting |
| Credentials for that number | Your workspace | The access token is sealed by `crypto` and never echoed back to a screen |
| Webhook delivery of inbound messages | Meta | One URL serves every workspace; `phone_number_id` in the payload finds the account |
| Person resolution and the conversation record | Connect | `identity.py` maps the number to a Person; the thread is canonical |
| Whether a reply is sent, approved or drafted | Connect | `whatsapp.dispatch` asks `autonomy.decide`, narrowest scope first |
| The 24-hour window, template approval and the billed category | Meta | Connect tracks the window per conversation and sends under Meta's category, not the one typed |
| Delivery and read reporting | Meta | Connect stores the statuses Meta posts back and claims nothing more |

> **Note** Credentials are per workspace. Two workspaces on the same deployment never share a WhatsApp number, and a customer session cannot read the Owner's Meta credentials — the same three isolation layers that protect mail protect this.

## Where to go next

- [Setting up WhatsApp](/docs/whatsapp/channel-setup/) — credentials, the webhook, and what to test first.
- [The WhatsApp business identity](/docs/whatsapp/provider-identity/) — what a customer sees at the top of the chat.
- [Receiving a WhatsApp message](/docs/whatsapp/inbound-webhook/) — verification, workspace resolution, the canonical record.
- [Recognising who sent a WhatsApp message](/docs/whatsapp/person-resolution/) — number to identity to Person.
- [Replying on WhatsApp](/docs/whatsapp/replying/) — the draft, the autonomy rule, the send.
- [What WhatsApp cannot do here](/docs/whatsapp/whatsapp-limits/) — the limits, stated plainly.

If you are configuring the channel for the first time, [Connecting WhatsApp, end to end](/docs/workflows/whatsapp-setup-workflow/) walks the whole path from credentials to a first verified inbound message, and is the fastest way to find out which half of the chain is not working.

## What this channel does not do

Connect does not run a WhatsApp Business account for you, does not obtain your number, does not submit templates for approval and does not decide whether a template is accepted. It also does not invent delivery information: a message with no status reported against it is shown as having no status, not as delivered.

Media is handled as Meta hands it over. Images, documents, audio, video and stickers arrive as a media id Connect fetches from the Graph API, and outbound media is uploaded first and then sent by id. Anything above 16 MB is refused before the upload, because Meta will refuse it too.

## Everything in this section

11 pages, each with its own status and the date it was last checked against the running system.

| Page | What it covers |
|---|---|
| [Continuing a WhatsApp conversation](/docs/whatsapp/conversation-continuity/) | What Connect carries from one WhatsApp message to the next: the thread, the relationship, memory and knowledge — and how a long silence is treated. |
| [Delivery and read status](/docs/whatsapp/message-status/) | Delivery and read receipts on WhatsApp: what Meta reports, what Connect stores, what it refuses to infer, and the billed category that rides along with a status. |
| [Follow-ups on WhatsApp](/docs/whatsapp/whatsapp-follow-up/) | Scheduling a WhatsApp follow-up: what can be promised, what Meta's 24-hour window allows, and what happens when the due time arrives and only a template will do. |
| [Opting out of WhatsApp](/docs/whatsapp/opt-out/) | What a customer can say to stop WhatsApp messages, how Connect honours it, where the suppression is recorded, and what still reaches them afterwards. |
| [Receiving a WhatsApp message](/docs/whatsapp/inbound-webhook/) | How a WhatsApp message reaches Connect: Meta's signed webhook call, which workspace it belongs to, every message type it can carry, and the record it becomes. |
| [Recognising who sent a WhatsApp message](/docs/whatsapp/person-resolution/) | How a WhatsApp number becomes a named Person in your relationships, what happens when the sender is unknown, and how a wrong match is corrected. |
| [Replying on WhatsApp](/docs/whatsapp/replying/) | How a WhatsApp reply is written, what decides whether it is sent or held for approval, and what counts as evidence that it actually went. |
| [Setting up WhatsApp](/docs/whatsapp/channel-setup/) | Connecting WhatsApp in a workspace: Official API credentials or Meta's QR-linked coexistence route, the webhook, the autonomy decision, and the test that proves it. |
| [The WhatsApp business identity](/docs/whatsapp/provider-identity/) | The number, the display name and the verification mark a customer sees on a WhatsApp chat: what Meta owns, what the connection mode changes, and what Connect cannot. |
| [What WhatsApp cannot do here](/docs/whatsapp/whatsapp-limits/) | The honest boundaries of WhatsApp in Connect: two things not proven in production, what Meta decides rather than Connect, and the limits that are Connect's own. |
| [WhatsApp for the Owner and for a customer](/docs/whatsapp/whatsapp-owner-tenant/) | One WhatsApp implementation, two audiences: what the Owner and a customer workspace share, what is separate, and why a test on one proves nothing about the other. |

## Questions

### Can Connect start a WhatsApp conversation with somebody who has never written?

Only with a template Meta has approved, sent under the category Meta gave it. A free-form message outside the 24-hour window is refused before the network call, and a template name Meta has not approved is refused too. See [Follow-ups on WhatsApp](/docs/whatsapp/whatsapp-follow-up/).

### Is WhatsApp a different agent from the one that answers email?

No. One engine reads every channel. The knowledge it grounds an answer in, the memory it applies and the rules it obeys are the same; only the channel rule in `autonomy.py` and the shape of the message differ.

### Do the Owner and a customer workspace share anything on this channel?

Only the implementation. Numbers, credentials, conversations and suppressions are per workspace. [WhatsApp for the Owner and for a customer](/docs/whatsapp/whatsapp-owner-tenant/) sets out exactly what is shared and what is not.

## Related

- [Setting up WhatsApp](https://connectbyjbrh.com/docs/whatsapp/channel-setup/)
- [Receiving a WhatsApp message](https://connectbyjbrh.com/docs/whatsapp/inbound-webhook/)
- [Replying on WhatsApp](https://connectbyjbrh.com/docs/whatsapp/replying/)
- [What WhatsApp cannot do here](https://connectbyjbrh.com/docs/whatsapp/whatsapp-limits/)
- [SMS in Connect](https://connectbyjbrh.com/docs/sms/)
- [Email in Connect](https://connectbyjbrh.com/docs/email/)
- [What Connect may do](https://connectbyjbrh.com/docs/autonomy/)

## What this page is based on

- Connect capability registry (docs-source/facts.py) — `WHATSAPP`, reconciled against `7f81e78`
- `backend/app/whatsapp.py` — connection modes, window, consent, `dispatch`
- `backend/app/whatsapp_engine.py` — answering, and what stops it
- `backend/app/whatsapp_api.py` — the webhook and the two routers
