← Back to PRs

#11484: feat: add WhatsApp pairing code login as alternative to QR scanning

by BlackScript open 2026-02-07 21:52 View on GitHub →
channel: whatsapp-web app: macos app: web-ui gateway stale
## Summary - Adds WhatsApp pairing code login as an alternative to QR code scanning - Users enter their phone number and receive an 8-digit code to type into WhatsApp instead of scanning a QR - Useful for headless servers, remote access, or when QR codes don't render properly ## How it works - Passing `phoneNumber` to `web.login.start` automatically switches to pairing code mode - The pairing code flow reuses the existing `ActiveLogin` / `waitForWebLogin` mechanism — no separate wait method needed - Dashboard shows a "Pair with Code" button next to the existing QR flow - The 8-digit code is displayed prominently in the UI ## Test plan - [x] `pnpm build` passes (all 4 build steps) - [x] Existing `login-qr.test.ts` passes (QR flow unaffected) - [x] Tested locally on own OpenClaw instance (headless server via Cloudflare Tunnel) - [ ] Manual test: trigger pairing code flow via dashboard - [ ] Manual test: verify QR flow still works as before - [ ] Manual test: verify "Wait for scan" button works for both flows ## AI Disclosure 🤖 This PR was built with **Claude Code (Claude Opus 4.6)** as a coding assistant. - **Degree of AI involvement:** Code was AI-assisted, with human review and direction for each change - **Testing:** Lightly tested — build passes, existing unit tests pass, manual end-to-end testing pending - **Understanding:** I understand the full scope of the changes — the pairing code flow hooks into Baileys' `requestPairingCode()` API, reuses the existing `ActiveLogin`/`waitForWebLogin` lifecycle, and extends the gateway schema with an optional `phoneNumber` parameter. The UI adds a secondary login path alongside the existing QR flow. ## Greptile Review Feedback All three issues raised by Greptile have been addressed in follow-up commits: - **Wrong wait messaging** → Added `mode` field (`"qr"` | `"pairing-code"`) to `ActiveLogin` so `waitForWebLogin` shows correct messages per flow (`c863cbf`) - **Forces relink unexpectedly** → Removed hardcoded `force: true` in pairing code controller, now defaults to `false` matching QR behavior (`c863cbf`) - **Pairing code left active** → `ActiveLogin` intentionally stays active after `requestPairingCode` succeeds because `waitForWebLogin` needs it for the connection handshake (documented in commit message) (`c863cbf`) - **Formatting + Swift models** → Ran formatter and regenerated `GatewayModels.swift` (`c63c4355`)

Most Similar PRs