# Connecting WhatsApp, end to end

Setup runs from a Meta credential set — phone number ID, WhatsApp Business account ID, access token, app secret — through a webhook handshake and a Verify that asks Meta about the number, to an autonomy decision, and ends with one real message from a phone in your hand. That message proves the inbound chain; the reply that follows proves the outbound one.

- **Status:** Available
- **Audience:** both
- **Channels:** whatsapp
- **In the app:** #/whatsapp-setup, #/whatsapp, #/autonomy
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/workflows/whatsapp-setup-workflow/

## The stages

1. Trigger — a workspace decides to run WhatsApp and picks a connection mode: its own Meta app and number, or Meta's QR-linked coexistence route.
2. User event — an administrator opens `#/whatsapp-setup` and enters the phone number ID, WhatsApp Business account ID, access token and app secret; on the QR route, accepts the mandatory warning word for word instead.
3. Authentication and workspace resolution — the change is made in one workspace by an identified person; Google OAuth is the only sign-in, the token and secret are encrypted at rest, and a QR consent is written to the audit trail with who accepted it.
4. Ingest — Meta is given the one webhook address and the verify token Connect generated; its `hub.mode=subscribe` handshake stamps the account as verified.
5. Canonical record — the account exists against the workspace at `pending`; Verify asks Meta about the number, stores the display number, verified name and quality rating, and moves it to `connected`.
6. Reasoning — nothing yet. No message has arrived, and Connect has nothing to think about until one does.
7. Knowledge, memory and rules — the workspace's Knowledge and any channel-tier standing instructions already apply, and templates are synced from Meta with their approved names, languages and categories.
8. Autonomy and approval — a mode is chosen for `whatsapp`: `off`, `draft_only`, `ask_before_send` or `autonomous`.
9. Action through Meta — the administrator sends one message from their own phone to the business number.
10. Result — the conversation appears on `#/whatsapp` and `#/inbox`, attached to a Person; a reply is sent or queued according to the mode.
11. Relationship, timeline and memory — the test conversation is a real relationship record and behaves like one; it is not a sandbox.
12. Audit, usage and Needs You — the configuration change and the first decision are both in the audit trail.

> **Note** Stage six is a real stage, not filler. Between registering the webhook and receiving a message the channel is configured and completely silent, and that silence is indistinguishable from a broken webhook. Only the test message tells the two apart.

## Stage by stage, with the failures

| Stage | What you see | What changes | What can fail |
|---|---|---|---|
| Credentials entered | A masked value confirming something is set | The account row at `pending`, token and secret encrypted | A number already connected to another workspace is refused outright |
| Webhook registered | The handshake succeeding in Meta's console | `webhook_verified_at` on the account | Registered against a different address — the commonest setup fault |
| Verify pressed | The display number and verified name appear | Status moves to `connected`, with Meta's quality rating | Meta rejects the credentials; the account holds `error` and what Meta said |
| Mode chosen | The channel on `#/autonomy` | The autonomy rule for `whatsapp` | Left `off`, which receives messages and answers nothing |
| Test message sent | A conversation appearing within seconds | A Person, a conversation, a message, an open 24-hour window | Nothing appears — the inbound half is not connected |
| Reply observed | The reply on your own phone | A send with Meta's message id behind it | Held by the mode, refused by consent, or refused by Meta |

The QR route stops earlier than any of that in production. The warning is accepted and audit-logged, the number is marked QR-linked, and the signup step then reports that QR linking is not switched on — Meta allows coexistence only for a Tech Provider or Solution Partner app with Embedded Signup. Nothing after consent can be tested there today.

> **Careful** Send the test from a number that is not already a contact if you also want to watch person resolution create a record. Testing from a number Connect already knows proves the webhook and tells you nothing about matching.

## Reading the result honestly

The two halves fail independently and the test distinguishes them. No conversation at all means Meta is not calling Connect: the webhook, its address, or the verify handshake. A conversation with no reply means the inbound chain works and something on the outbound side stopped it — the mode, a consent rule, the window, or Meta.

Do the test as both audiences if the workspace you are configuring is a customer's. An Owner session and a customer session take different API paths to the same code, and a customer workspace also meets plan allowances the Owner never touches. A configuration proved on one account is not proved on the other.

## After it works

1. Decide the channel's standing instructions — length and register on a chat channel are not what they are on email.
2. Check what the endpoint should remember: a direction attached to the number applies to every contact on it.
3. Sync templates and nominate the one follow-ups should use, before a closed window makes it urgent.
4. Move off `ask_before_send` only after reading enough drafts to know what your Knowledge is missing.

[Verifying a channel actually works](/docs/workflows/channel-verification/) generalises this test to every channel, and is the habit worth keeping whenever a channel credential changes.

## Questions

### How long should the test message take to appear?

Seconds, when the webhook is right. A minute of nothing is not slowness; it is the inbound half not being connected, and Meta's webhook configuration is where to look.

### Can I set this up without a Meta account of my own?

Only through the QR route, which uses Connect's Meta app rather than yours — and that route cannot complete in production, because Meta requires a Tech Provider or Solution Partner app with Embedded Signup for coexistence. Connect does not obtain a WhatsApp Business account or a number for you.

### Does re-entering credentials break the existing conversations?

No. Conversations, people and memory belong to the workspace, not to the credential. Replacing a rotated token restores sending and leaves the history alone.

## Related

- [Setting up WhatsApp](https://connectbyjbrh.com/docs/whatsapp/channel-setup/)
- [WhatsApp in Connect](https://connectbyjbrh.com/docs/whatsapp/)
- [WhatsApp messages are not arriving](https://connectbyjbrh.com/docs/troubleshooting/whatsapp-not-receiving/)
- [Configuring a channel, end to end](https://connectbyjbrh.com/docs/workflows/channel-configuration/)
- [Verifying a channel actually works](https://connectbyjbrh.com/docs/workflows/channel-verification/)
- [WhatsApp for the Owner and for a customer](https://connectbyjbrh.com/docs/whatsapp/whatsapp-owner-tenant/)

## What this page is based on

- `backend/app/whatsapp.py` — `connect`, `verify_handshake`, `verify_connection`, `record_qr_consent`, `complete_qr`
- `backend/app/whatsapp_api.py` — the setup routes behind both audiences
- `docs-source/sources/GENERAL.md` §1 — two audiences, §10 — sealed credentials and Google-only sign-in
- Connect capability registry (docs-source/facts.py) — `WHATSAPP`, `autonomy_modes`
