# WhatsApp

URL: https://cogitator.app/docs/channels/whatsapp

> Connect your AI agent to WhatsApp via Baileys.

## Setup

```bash
pnpm add @whiskeysockets/baileys
pnpm add qrcode-terminal   # optional: print the pairing QR in the terminal
```

## How It Works

WhatsApp doesn't have a bot API like Telegram. Instead, Baileys connects as a "linked device" to your personal WhatsApp account (like WhatsApp Web). This means:

* Your agent responds **as your WhatsApp number**
* No separate bot account needed
* Works with personal and business WhatsApp

## First-Time Pairing

1. Start the gateway — a QR code appears in the terminal (requires `qrcode-terminal`; otherwise pass `qrCallback`)
2. On your phone: WhatsApp → Settings → Linked Devices → Link a Device
3. Scan the QR code
4. Session is saved to disk — next restart reconnects automatically

## Usage

```typescript
import { Gateway, whatsappChannel } from '@cogitator-ai/channels';

const whatsapp = whatsappChannel({
  sessionPath: '.cogitator/whatsapp-session',
  printQr: true,
});

const gateway = new Gateway({ agent, cogitator, channels: [whatsapp] });
await gateway.start();
```

## Use with `cogitator up`

Add a `whatsapp` entry to `cogitator.yml` (the wizard does not ask about it, but `cogitator wizard --edit` keeps it):

```yaml title="cogitator.yml"
channels:
  whatsapp:
    ownerIds:
      - '15551234567' # phone number without @s.whatsapp.net
    sessionPath: ~/.cogitator/whatsapp-session # default
```

`cogitator up` (or `RuntimeBuilder`) starts the channel with the QR printed in the terminal on first run. `ownerIds` work like on other channels: the first one gets owner commands and self-config access. See the [config reference](/docs/channels/wizard#config-reference).

## Configuration

```typescript
interface WhatsAppChannelConfig {
  sessionPath?: string; // default: '.cogitator/whatsapp-session'
  qrCallback?: (qr: string) => void; // takes precedence over printQr
  printQr?: boolean; // default: true, uses qrcode-terminal
}
```

## Features

| Feature             | Support                                                          |
| ------------------- | ---------------------------------------------------------------- |
| 1-on-1 chats        | ✅                                                                |
| Group chats         | ✅                                                                |
| Streaming (edit)    | ✅ via message edits                                              |
| Typing indicator    | ✅ (presence update)                                              |
| Reactions           | ❌                                                                |
| Incoming media      | ✅ images, voice, video, documents (+ captions)                   |
| Sending files       | ✅ image / audio / video / document by type, from buffers or URLs |
| Quoted replies      | ✅ for recent messages                                            |
| Markdown            | ✅ WhatsApp-native formatting                                     |
| Auto-reconnect      | ✅ exponential backoff (1s → 60s), not after `stop()` or logout   |
| Session persistence | ✅ (filesystem)                                                   |

### User ids

Baileys 6 and 7 both work. WhatsApp increasingly addresses people by a private id (LID, `...@lid`) instead of their phone number; Baileys 7 passes the number along when WhatsApp shares it. A message's `userId` is the phone number whenever it is known — so owner lists and per-user memory keep matching — and the LID only for someone whose number WhatsApp hides. Replies go to the chat the message came from either way: `channelId` is the chat JID (the group JID in groups, where `groupId` is set too). Messages you send yourself from the linked phone are ignored.

## WhatsApp Markdown

WhatsApp uses its own formatting syntax. Cogitator auto-converts standard markdown before sending:

| Standard      | WhatsApp     |
| ------------- | ------------ |
| `**bold**`    | `*bold*`     |
| `__bold__`    | `*bold*`     |
| `~~strike~~`  | `~strike~`   |
| `# Heading`   | `*Heading*`  |
| `[text](url)` | `text (url)` |
| Code blocks   | Preserved    |
| Inline code   | Preserved    |

## Limitations

* QR code expires after \~20 seconds, bot retries automatically
* If you unlink the device from your phone (logout), the channel stops reconnecting; delete the `sessionPath` directory and restart to pair again
* WhatsApp may temporarily ban automated accounts with high message volume

## Tips

* Use a dedicated phone number for production bots
* The `sessionPath` directory must be writable
* Use `qrCallback` to display the QR in a web UI instead of terminal
