WhatsApp (canal web)

Estado: listo para producción vía WhatsApp Web (Baileys). El gateway gestiona las sesiones vinculadas.

Configuración rápida

Paso 1: Configura la política de acceso de WhatsApp

{
  channels: {
    whatsapp: {
      dmPolicy: "pairing",
      allowFrom: ["+15551234567"],
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15551234567"],
    },
  },
}

Paso 2: Vincula WhatsApp (QR)

openclaw channels login --channel whatsapp
Para una cuenta específica:
openclaw channels login --channel whatsapp --account work

Paso 3: Inicia el gateway

openclaw gateway

Paso 4: Aprueba la primera solicitud de emparejamiento (si usas modo emparejamiento)

openclaw pairing list whatsapp
openclaw pairing approve whatsapp <CODE>
Las solicitudes de emparejamiento expiran después de 1 hora. Las solicitudes pendientes están limitadas a 3 por canal.

Nota: OpenClaw recomienda ejecutar WhatsApp con un número separado cuando sea posible. (Los metadatos del canal y el flujo de onboarding están optimizados para esa configuración, pero las configuraciones con número personal también son compatibles.)

Patrones de despliegue

Número dedicado (recomendado)
Este es el modo operativo más limpio:

- identidad de WhatsApp separada para OpenClaw
- límites de listas de permitidos y enrutamiento de mensajes directos más claros
- menor probabilidad de confusión por self-chat

Patrón de política mínima:

```json5
{
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551234567"],
    },
  },
}
```
Respaldo con número personal
El onboarding admite modo de número personal y escribe una línea base compatible con self-chat:

- `dmPolicy: "allowlist"`
- `allowFrom` incluye tu número personal
- `selfChatMode: true`

En runtime, las protecciones de self-chat se basan en el número self vinculado y `allowFrom`.

Modelo de runtime

  • El gateway gestiona el socket de WhatsApp y el bucle de reconexión.
  • Los envíos salientes requieren un listener de WhatsApp activo para la cuenta destino.
  • Los chats de estado y difusión se ignoran (@status, @broadcast).
  • Los chats directos usan reglas de sesión de mensajes directos (session.dmScope; por defecto main unifica los mensajes directos en la sesión principal del agente).
  • Las sesiones de grupo están aisladas (agent:<agentId>:whatsapp:group:<jid>).

Control de acceso y activación

Política de mensajes directos

`channels.whatsapp.dmPolicy` controla el acceso a chats directos:

- `pairing` (predeterminado)
- `allowlist`
- `open` (requiere que `allowFrom` incluya `"*"`)
- `disabled`

`allowFrom` acepta números estilo E.164 (normalizados internamente).

Excepción multicuenta: `channels.whatsapp.accounts.<id>.dmPolicy` (y `allowFrom`) tienen prioridad sobre los valores predeterminados del canal para esa cuenta.

Política de grupo + listas de permitidos

El acceso a grupos tiene dos niveles:

1. **Lista de permitidos de membresía de grupo** (`channels.whatsapp.groups`)
   - si `groups` se omite, todos los grupos son elegibles
   - si `groups` está presente, actúa como lista de permitidos de grupo (`"*"` permitido)

2. **Política de remitente de grupo** (`channels.whatsapp.groupPolicy` + `groupAllowFrom`)
   - `open`: la lista de permitidos de remitente se evita
   - `allowlist`: el remitente debe coincidir con `groupAllowFrom` (o `*`)
   - `disabled`: bloquear toda entrada de grupo

Alternativa de lista de permitidos de remitente:

- si `groupAllowFrom` no está establecido, el runtime recurre a `allowFrom` cuando está disponible
- las listas de permitidos de remitente se evalúan antes de la activación por mención/respuesta

Nota: si no existe ningún bloque `channels.whatsapp`, el respaldo de política de grupo del runtime es `allowlist` (con un registro de advertencia), incluso si `channels.defaults.groupPolicy` está establecido.

Menciones + /activation

Las respuestas de grupo requieren mención por defecto.

La detección de menciones incluye:

- menciones explícitas de WhatsApp de la identidad del bot
- patrones regex de mención configurados (`agents.list[].groupChat.mentionPatterns`, alternativa `messages.groupChat.mentionPatterns`)
- detección implícita de respuesta al bot (el remitente de la respuesta coincide con la identidad del bot)

Nota de seguridad:

- la cita/respuesta solo satisface el control por mención; **no** otorga autorización de remitente
- con `groupPolicy: "allowlist"`, los remitentes no incluidos en la lista de permitidos siguen bloqueados incluso si responden al mensaje de un usuario autorizado

Comando de activación a nivel de sesión:

- `/activation mention`
- `/activation always`

`activation` actualiza el estado de la sesión (no la configuración global). Está controlado por el propietario.

Comportamiento de número personal y self-chat

Cuando el número self vinculado también está presente en allowFrom, se activan las protecciones de self-chat de WhatsApp:

  • omitir acuses de lectura para turnos de self-chat
  • ignorar el comportamiento de auto-activación de mention-JID que de otra forma te notificaría a ti mismo
  • si messages.responsePrefix no está establecido, las respuestas de self-chat usan por defecto [{identity.name}] o [openclaw]

Normalización de mensajes y contexto

Sobre entrante + contexto de respuesta
Los mensajes entrantes de WhatsApp se envuelven en el sobre entrante compartido.

Si existe una respuesta citada, el contexto se añade en esta forma:

```text
[Replying to <sender> id:<stanzaId>]
<quoted body or media placeholder>
[/Replying]
```

Los campos de metadatos de respuesta también se rellenan cuando están disponibles (`ReplyToId`, `ReplyToBody`, `ReplyToSender`, sender JID/E.164).
Placeholders de medios y extracción de ubicación/contacto
Los mensajes entrantes solo de medios se normalizan con placeholders como:

- `<media:image>`
- `<media:video>`
- `<media:audio>`
- `<media:document>`
- `<media:sticker>`

Los payloads de ubicación y contacto se normalizan en contexto textual antes del enrutamiento.
Inyección de historial de grupo pendiente
Para grupos, los mensajes no procesados pueden almacenarse en búfer e inyectarse como contexto cuando el bot finalmente se activa.

- límite por defecto: `50`
- config: `channels.whatsapp.historyLimit`
- alternativa: `messages.groupChat.historyLimit`
- `0` desactiva
Acuses de lectura
Los acuses de lectura están activados por defecto para los mensajes entrantes de WhatsApp aceptados.

Desactivar globalmente:

```json5
{
  channels: {
    whatsapp: {
      sendReadReceipts: false,
    },
  },
}
```

Los turnos de self-chat omiten los acuses de lectura incluso cuando están activados globalmente.

Entrega, fragmentación y medios

Fragmentación de texto
- límite de fragmento por defecto: `channels.whatsapp.textChunkLimit = 4000`
- `channels.whatsapp.chunkMode = "length" | "newline"`
- el modo `newline` prefiere límites de párrafo (líneas en blanco), luego recurre a fragmentación segura por longitud
Comportamiento de medios salientes
- admite payloads de imagen, video, audio (nota de voz PTT) y documento
- `audio/ogg` se reescribe a `audio/ogg; codecs=opus` para compatibilidad con notas de voz
- la reproducción de GIF animados es compatible vía `gifPlayback: true` en envíos de video
- los subtítulos se aplican al primer elemento de medios al enviar payloads de respuesta multi-media
- la fuente de medios puede ser HTTP(S), `file://` o rutas locales
Límites de tamaño de medios y comportamiento de respaldo
- límite de guardado de medios entrantes: `channels.whatsapp.mediaMaxMb` (por defecto `50`)
- límite de envío de medios salientes: `channels.whatsapp.mediaMaxMb` (por defecto `50`)
- excepciones por cuenta usan `channels.whatsapp.accounts.<accountId>.mediaMaxMb`
- las imágenes se auto-optimizan (redimensionar/barrido de calidad) para ajustarse a los límites
- en caso de fallo de envío de medios, el respaldo del primer elemento envía una advertencia de texto en vez de descartar la respuesta silenciosamente

Reacciones de confirmación

WhatsApp admite reacciones de confirmación inmediata al recibir mensajes entrantes vía channels.whatsapp.ackReaction.

{
  channels: {
    whatsapp: {
      ackReaction: {
        emoji: "👀",
        direct: true,
        group: "mentions", // always | mentions | never
      },
    },
  },
}

Notas de comportamiento:

  • se envía inmediatamente después de que el entrante sea aceptado (antes de la respuesta)
  • los fallos se registran pero no bloquean la entrega normal de respuestas
  • el modo de grupo mentions reacciona en turnos activados por mención; la activación de grupo always actúa como bypass para esta verificación
  • WhatsApp usa channels.whatsapp.ackReaction (el legacy messages.ackReaction no se usa aquí)

Multicuenta y credenciales

Selección de cuenta y valores predeterminados
- los IDs de cuenta vienen de `channels.whatsapp.accounts`
- selección de cuenta predeterminada: `default` si está presente, de lo contrario el primer ID de cuenta configurado (ordenado)
- los IDs de cuenta se normalizan internamente para búsqueda
Rutas de credenciales y compatibilidad legacy
- ruta de autenticación actual: `~/.openclaw/credentials/whatsapp/<accountId>/creds.json`
- archivo de respaldo: `creds.json.bak`
- la autenticación legacy predeterminada en `~/.openclaw/credentials/` sigue reconociéndose/migrándose para flujos de cuenta predeterminada
Comportamiento de cierre de sesión
`openclaw channels logout --channel whatsapp [--account <id>]` limpia el estado de autenticación de WhatsApp para esa cuenta.

En directorios de autenticación legacy, `oauth.json` se preserva mientras se eliminan los archivos de autenticación de Baileys.

Herramientas, acciones y escrituras de configuración

  • El soporte de herramientas del agente incluye la acción de reacción de WhatsApp (react).
  • Puertas de acciones:
    • channels.whatsapp.actions.reactions
    • channels.whatsapp.actions.polls
  • Las escrituras de configuración iniciadas desde el canal están activadas por defecto (desactivar vía channels.whatsapp.configWrites=false).

Solución de problemas

No vinculado (se requiere QR)
Síntoma: el estado del canal reporta no vinculado.

Solución:

```bash
openclaw channels login --channel whatsapp
openclaw channels status
```
Vinculado pero desconectado / bucle de reconexión
Síntoma: cuenta vinculada con desconexiones o intentos de reconexión repetidos.

Solución:

```bash
openclaw doctor
openclaw logs --follow
```

Si es necesario, vuelve a vincular con `channels login`.
Sin listener activo al enviar
Los envíos salientes fallan inmediatamente cuando no existe un listener activo del gateway para la cuenta destino.

Asegúrate de que el gateway esté en ejecución y la cuenta esté vinculada.
Mensajes de grupo ignorados inesperadamente
Verifica en este orden:

- `groupPolicy`
- `groupAllowFrom` / `allowFrom`
- entradas de lista de permitidos `groups`
- control por mención (`requireMention` + patrones de mención)
- claves duplicadas en `openclaw.json` (JSON5): las entradas posteriores sobrescriben las anteriores, así que mantén un solo `groupPolicy` por alcance
Advertencia de runtime Bun
El runtime del gateway de WhatsApp debe usar Node. Bun está marcado como incompatible para la operación estable del gateway de WhatsApp/Telegram.

Referencia de configuración

Referencia principal:

Campos clave de WhatsApp:

  • acceso: dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups
  • entrega: textChunkLimit, chunkMode, mediaMaxMb, sendReadReceipts, ackReaction
  • multicuenta: accounts.<id>.enabled, accounts.<id>.authDir, excepciones a nivel de cuenta
  • operaciones: configWrites, debounceMs, web.enabled, web.heartbeatSeconds, web.reconnect.*
  • comportamiento de sesión: session.dmScope, historyLimit, dmHistoryLimit, dms.<id>.historyLimit

Relacionado