> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenClaw

> Connect OpenClaw agents to WhatsApp with Kapso.

Use `@kapso/openclaw-whatsapp` when an OpenClaw agent needs to send and receive WhatsApp messages through Kapso.

Use [`@kapso/whatsapp-cloud-api`](/docs/whatsapp/typescript-sdk/introduction) directly when you are building your own app and do not need OpenClaw channel routing.

## Installation

Requires OpenClaw >= 2026.5.27.

```bash theme={null}
openclaw plugins install clawhub:@kapso/openclaw-whatsapp
openclaw config set 'plugins.allow' '["codex","kapso-whatsapp"]' --strict-json
openclaw config set 'channels["kapso-whatsapp"].enabled' true --strict-json
```

If `plugins.allow` already has entries, keep them and add `kapso-whatsapp`.

OpenClaw resolves the plugin from ClawHub and installs runtime dependencies, including `@kapso/whatsapp-cloud-api` and `@kapso/cli`. No separate `npm install` is needed.

The Kapso CLI is bundled with the plugin:

```bash theme={null}
openclaw kapso-whatsapp cli login
openclaw kapso-whatsapp cli status
```

## Setup

Requires:

| Requirement              | Use                                                       |
| ------------------------ | --------------------------------------------------------- |
| Kapso API key            | Sends messages, resolves numbers, and registers webhooks. |
| WhatsApp sender number   | The Kapso-connected number your agent sends from.         |
| Public HTTPS gateway URL | Receives Kapso webhooks.                                  |
| Webhook secret           | Verifies inbound webhook signatures.                      |

After your OpenClaw gateway has a public URL, let the plugin resolve the number, register the webhook, and write config:

```bash theme={null}
openclaw kapso-whatsapp setup \
  --api-key "kapso_..." \
  --phone-number "+15551234567" \
  --webhook-url "https://your-machine.your-tailnet.ts.net/kapso/webhook" \
  --webhook-secret "$(openssl rand -hex 32)" \
  --default-to "+15551234567" \
  --register-webhook \
  --write-config
```

If you already know the Kapso/Meta `phone_number_id`, use `--phone-number-id`:

```bash theme={null}
openclaw kapso-whatsapp setup \
  --api-key "kapso_..." \
  --phone-number-id "1234567890" \
  --webhook-url "https://your-openclaw-host.example.com/kapso/webhook" \
  --webhook-secret "$(openssl rand -hex 32)" \
  --register-webhook \
  --write-config
```

Useful setup flags:

| Flag            | Use                                                           |
| --------------- | ------------------------------------------------------------- |
| `--default-to`  | Default outbound WhatsApp recipient.                          |
| `--allow-from`  | Comma-separated inbound allowlist.                            |
| `--dm-security` | `allowlist`, `open`, or `disabled`.                           |
| `--dry-run`     | Print actions without writing config or registering webhooks. |
| `--json`        | Print machine-readable setup output.                          |

Omit `--write-config` to print the `openclaw config set` commands without applying them.

## Agent setup

The plugin ships an OpenClaw skill named `kapso-whatsapp-setup`.

Check that OpenClaw sees it:

```bash theme={null}
openclaw skills list | grep kapso
openclaw skills info kapso-whatsapp-setup
```

Before asking the agent to finish setup, do the interactive and secret-bearing steps yourself:

```bash theme={null}
openclaw kapso-whatsapp cli login
openclaw kapso-whatsapp cli status
openclaw config set 'channels["kapso-whatsapp"].apiKey' '"kapso_..."' --strict-json
```

Use the browser dashboard for setup visibility:

```bash theme={null}
openclaw dashboard
```

If you prefer the terminal UI, start `openclaw tui` and send:

```text theme={null}
/verbose full
/trace on
/tools verbose
```

Then paste something like this into OpenClaw:

```text theme={null}
Use the kapso-whatsapp-setup skill to finish my Kapso WhatsApp OpenClaw setup.

I already configured my Kapso API key on this server.
I already ran openclaw kapso-whatsapp cli login successfully.
Default outbound recipient: +15551234567
Public gateway: discover it if possible. I am using Tailscale Funnel on this machine.
Kapso WhatsApp sender number: discover it with the Kapso CLI. If there is more than one available number, ask me which one to use.

Please verify the Kapso CLI and @kapso/openclaw-whatsapp plugin are installed, but do not run interactive login. Discover the public webhook URL, resolve the phone_number_id, generate a webhook secret, register the Kapso phone-number webhook for whatsapp.message.received, write the OpenClaw channel config, set the default outbound recipient, run diagnostics, and tell me exactly what remains manual.
```

If you already know the public webhook URL, replace the gateway line with:

```text theme={null}
Public gateway webhook URL: https://your-openclaw-host.example.com/kapso/webhook
```

If you use another public tunnel or reverse proxy, name it:

```text theme={null}
Public gateway: discover it if possible. I am using ngrok on this machine.
```

If you already know the Kapso/Meta number ID, replace the sender-number line with:

```text theme={null}
Kapso/Meta phone_number_id: 1234567890
```

If the Kapso CLI is not logged in, the agent should stop and ask you to run `openclaw kapso-whatsapp cli login` in your terminal. It should not run interactive login for you.

## Public gateway

Kapso Cloud must reach your OpenClaw webhook over the public internet. A private tailnet URL is not enough.

For Tailscale, use Funnel:

```bash theme={null}
mkdir -p ~/.openclaw
openssl rand -base64 32 > ~/.openclaw/gateway-password
chmod 600 ~/.openclaw/gateway-password

openclaw gateway run \
  --bind loopback \
  --auth password \
  --password-file ~/.openclaw/gateway-password \
  --tailscale funnel \
  --force
```

Use `--password-file` instead of passing a password directly in process arguments.

The Kapso webhook URL should use your Funnel hostname plus `/kapso/webhook`:

```text theme={null}
https://your-machine.your-tailnet.ts.net/kapso/webhook
```

Discover an existing Funnel URL from the machine running OpenClaw:

```bash theme={null}
tailscale funnel status --json
```

## Configure manually

```bash theme={null}
openclaw config set 'channels["kapso-whatsapp"].apiKey' '"kapso_..."' --strict-json
openclaw config set 'channels["kapso-whatsapp"].phoneNumberId' '"1234567890"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].webhookSecret' '"shared webhook secret"' --strict-json
```

Use JSON strings for IDs and secrets, especially digit-only values. Current plugin versions coerce numeric `phoneNumberId` and `defaultTo` values, but JSON strings avoid precision loss for large IDs.

Optional settings:

```bash theme={null}
openclaw config set 'channels["kapso-whatsapp"].baseUrl' '"https://api.kapso.ai/meta/whatsapp"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].webhookPath' '"/kapso/webhook"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].defaultTo' '"+15551234567"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].dmSecurity' '"allowlist"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].allowFrom' '["+15551234567","15551234567"]' --strict-json
```

Kapso webhook sender IDs often arrive as digits-only values, while users usually type E.164 numbers with `+`. Current plugin versions compare both forms as the same sender. Including both is harmless for older installs or raw config edits.

You can also use environment variables:

```bash theme={null}
export KAPSO_API_KEY="kapso_..."
export KAPSO_PHONE_NUMBER_ID="1234567890"
export KAPSO_WEBHOOK_SECRET="shared webhook secret"
export KAPSO_BASE_URL="https://api.kapso.ai/meta/whatsapp"
export KAPSO_WEBHOOK_PATH="/kapso/webhook"
export KAPSO_BOT_USERNAME="support"
export KAPSO_DEFAULT_TO="+15551234567"
```

## Kapso webhook

Create a phone-number scoped Kapso webhook, not a project webhook.

| Setting         | Value                                                                              |
| --------------- | ---------------------------------------------------------------------------------- |
| Method          | `POST`                                                                             |
| URL             | `https://your-openclaw-host.example.com/kapso/webhook`                             |
| Events          | `whatsapp.message.received`                                                        |
| Secret          | Same value as `channels["kapso-whatsapp"].webhookSecret` or `KAPSO_WEBHOOK_SECRET` |
| Payload version | `v2` recommended                                                                   |

The setup command can register this webhook with `--register-webhook`.

You can also run the bundled Kapso CLI through OpenClaw:

```bash theme={null}
openclaw kapso-whatsapp cli login
openclaw kapso-whatsapp cli status
openclaw kapso-whatsapp cli whatsapp numbers list --output json
openclaw kapso-whatsapp cli whatsapp numbers resolve "+15551234567" --output json
openclaw kapso-whatsapp cli whatsapp webhooks new \
  --phone-number-id "1234567890" \
  --url "https://your-openclaw-host.example.com/kapso/webhook" \
  --event whatsapp.message.received \
  --active \
  --output json
```

The setup command uses the bundled CLI internally for number resolution, project access checks, and webhook registration.

## Channel targets

The plugin accepts WhatsApp phone-number targets with these prefixes:

```text theme={null}
kapso:+15551234567
kapso-whatsapp:+15551234567
whatsapp:+15551234567
wa:+15551234567
```

Plain E.164 or digits-only phone numbers also work.

Set a default recipient when you want OpenClaw to send through this channel without an explicit target:

```bash theme={null}
openclaw config set 'channels["kapso-whatsapp"].defaultTo' '"+15551234567"' --strict-json
```

## Diagnostics

Check config and webhook registration:

```bash theme={null}
openclaw kapso-whatsapp setup --help
openclaw kapso-whatsapp doctor
openclaw kapso-whatsapp doctor --json
openclaw config get 'channels["kapso-whatsapp"]'
openclaw channels status --channel kapso-whatsapp --probe
```

Tail OpenClaw logs:

```bash theme={null}
openclaw logs --follow --plain --limit 500
openclaw channels logs --lines 500 | grep -Ei 'kapso|whatsapp|media|image|audio|document|webhook|signature'
```

If the gateway prints a log path, tail it directly:

```bash theme={null}
tail -f /tmp/openclaw/openclaw-YYYY-MM-DD.log
```

## Media

Images, videos, and documents can be forwarded when Kapso includes a downloadable media URL, such as `mediaUrl`, `media_data.url`, `media_data.downloadUrl`, or a direct media `link` or `url`.

The selected OpenClaw model/runtime must support that media type.

If Kapso sends only a media ID and no URL, the plugin records that media exists but cannot pass the file bytes to the model. Logs warn about `id but no URL`.

Voice notes and audio messages need a transcription provider. Without one, the agent may only receive audio metadata. Hosted options include OpenAI `gpt-4o-transcribe`, `gpt-4o-mini-transcribe`, or `whisper-1`. Self-hosted ASR can work if your OpenClaw deployment exposes a compatible transcription provider.

## Troubleshooting

### Config values rejected as "must be string"

Use strict JSON strings:

```bash theme={null}
openclaw config set 'channels["kapso-whatsapp"].phoneNumberId' '"1234567890"' --strict-json
openclaw config set 'channels["kapso-whatsapp"].defaultTo' '"+15551234567"' --strict-json
```

### Webhook returns 401

The Kapso webhook secret and `channels["kapso-whatsapp"].webhookSecret` do not match, or the request is missing the Kapso signature header.

### Webhook is reachable but no messages arrive

Confirm the webhook is phone-number scoped and subscribed to `whatsapp.message.received`. Project webhooks do not receive WhatsApp message events.

### Webhook dispatches but no agent session or reply

Check `allowFrom`. Kapso commonly sends inbound sender IDs without a leading `+`, even if your allowlist was configured with E.164 values.

Current plugin versions compare those forms as the same sender. On older installs, include both variants and restart the gateway:

```bash theme={null}
openclaw config set 'channels["kapso-whatsapp"].allowFrom' '["+56975746426","56975746426"]' --strict-json
```

### Images sometimes work and sometimes do not

Check logs for `media=image/url=yes`. If logs say `url=no` or warn that the event had an ID but no URL, the model did not receive the actual image bytes.

## Source

<Card title="GitHub repository" icon="github" href="https://github.com/gokapso/openclaw-plugin">
  Source code, setup skill, and issue tracker for `@kapso/openclaw-whatsapp`.
</Card>
