Instances
An instance is one logical WhatsApp connection — one phone number, one paired session, one set of webhooks. Every message you send and every message you receive belongs to exactly one instance.
Lifecycle
Instances move through a finite state machine. The status field on the API mirrors the FSM 1:1:
┌──────────────────┐
create → │ pending │ — instance row exists, no socket yet
└────────┬─────────┘
│ start session
▼
┌──────────────────┐
│ qr_required │ — Baileys produced a QR, waiting for scan
└────────┬─────────┘
scan │ timeout / cancel
▼
┌──────────────────┐
│ connected │ — session live; can send + receive
└────┬─────┬───────┘
network │ │ user logout / sessionInvalidated
blip │ ▼
┌──┴───────────────┐
│ reconnecting │
└────────┬─────────┘
│ recovery fails
▼
┌──────────────────┐
│ disconnected │ — needs human to re-pair
└──────────────────┘
Notable transitions:
pending → qr_requiredhappens lazily on the firstGET /v1/instances/:id/qrcall. We don't burn a Baileys socket until you ask.connected → reconnectingis automatic on transient socket errors. The manager backs off with jitter and tries to resume the session from the persisted auth-state.reconnecting → disconnectedhappens when WhatsApp explicitly invalidates the session (sessionInvalidated). This means the user logged out from another device, banned the number, or hit a Baileys protocol mismatch. The auth-state is wiped; you'll need a fresh QR scan to reconnect.
The event stream and the instance.connected / instance.disconnected webhooks emit on every transition.
Listing and creation
You can have multiple instances per customer — one per number you want to use. There's no hard cap in the schema, but each connected instance holds a WebSocket and ~20 MB of memory in the Node process, so a single backend can comfortably hold ~50 active sessions.
Create an instance
curl -sX POST "$WHATISUP_API/v1/instances" \
-H "Authorization: Bearer $WHATISUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"support-line"}'List your instances
curl -s "$WHATISUP_API/v1/instances" \
-H "Authorization: Bearer $WHATISUP_API_KEY"Names are free-form; they're for humans, not routing.
Soft-delete
DELETE /v1/instances/:id doesn't drop the row — it stops the Baileys socket, wipes the on-disk auth-state, and sets deleted_at. Webhook deliveries and audit events that reference this instance stay queryable. If you re-create with the same name, you get a brand-new id.
Deleting an instance does not unlink the device on the WhatsApp side. The user remains paired until either the gateway emits a logout (which Baileys does automatically on auth-state wipe) or the user manually unlinks from the phone's Linked devices screen.
Heartbeat and reconciliation
The session manager runs a heartbeat tick (default 30s, configurable via HEARTBEAT_INTERVAL_MS) that:
- Bumps
last_seen_atfor every connected session — observability for soft-stuck sockets. - Reconciles each in-memory session against the DB row. If the row is gone (hard delete or out-of-band SQL), the stale socket is stopped.
This is invisible to your application; you'll just notice that orphan sessions don't pile up.