# Connecting a shop's WhatsApp

> QR-code connect flow, polling, and disconnecting a shop's WhatsApp session.

# Connecting a shop's WhatsApp

| Method | Path | Permission | Purpose |
|---|---|---|---|
| GET | `/shops/{idOrName}/channels/whatsapp` | `whatsapp.read` | stored channel state + live session |
| POST | `/shops/{idOrName}/channels/whatsapp/connect` | `whatsapp.connect` | start connecting; returns a QR or `connected` |
| GET | `/shops/{idOrName}/channels/whatsapp/connect` | `whatsapp.connect` | poll until `connected` (latest QR each call) |
| POST | `/shops/{idOrName}/channels/whatsapp/disconnect` | `whatsapp.connect` | stop the session, keep the configuration |

## Flow

```
POST …/channels/whatsapp/connect
→ { "status": "qr_waiting", "qr": "<raw>",
    "qrImageDataUrl": "data:image/png;base64,…",
    "expiresAt": "…", "pollAfterMs": 3000, "channelConfigId": "…" }

GET  …/channels/whatsapp/connect        (every pollAfterMs)
→ { "status": "qr_waiting", … }         (the QR rotates every ~20–60s — always show the latest)
→ { "status": "connected", "phone": "24177000000", … }
```

Other statuses: `starting` (the bot is booting — poll again) and
`disconnected` (the session dropped — `POST connect` again). Polling before
any `POST` returns `409 WHATSAPP_NOT_CONFIGURED`.

Once `connected` arrives the API persists exactly what the dashboard's own QR
modal does (channel state, the shop's `channelStatus.whatsapp`, the owner
notification number). The WhatsApp session credentials themselves are stored
encrypted by the bot the instant the phone scans the code — they never
transit this API.

## Disconnect

`POST …/channels/whatsapp/disconnect` stops the live session but keeps the
channel's configuration, so a later `connect` reuses it (and its quota slot)
rather than starting over. Returns `404 WHATSAPP_NOT_CONFIGURED` if the shop
never had a WhatsApp channel at all.
