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

# WhatsApp

> Talk to ChatCLI on WhatsApp through the WhatsApp Business Cloud API: a verified, signed webhook the gateway serves, with voice and image messages in and image replies.

The WhatsApp adapter uses Meta's **WhatsApp Business Cloud API**. Meta delivers messages to a webhook the gateway serves, so the endpoint must be reachable over HTTPS from the internet, and every delivery is checked against your app secret.

| | WhatsApp |
| - | - |
| Transport | Cloud API webhook served by the gateway; replies through the Graph API |
| Who can talk to the bot | Anyone who messages the business number; there is no sender allow-list |
| Voice notes in | Yes |
| Voice replies | No (text only) |
| Images in | Yes (the caption is not read) |
| Images out | Yes |
| "Working on it" signal | One short text notice if the reply takes more than about 2 seconds |

## Set it up

<Steps>
  <Step title="Prepare the Meta app">
    In Meta for Developers, create an app with the **WhatsApp** product. Note the **access token**, the **phone number ID** of the number that will answer, and the app's **App Secret** (App settings → Basic). Choose a **verify token** of your own: any string you will type in both places.
  </Step>

  <Step title="Configure ChatCLI">
    ```bash theme={"system"}
    export CHATCLI_WHATSAPP_ACCESS_TOKEN="..."
    export CHATCLI_WHATSAPP_PHONE_ID="123456789012345"
    export CHATCLI_WHATSAPP_APP_SECRET="..."          # verifies every delivery
    export CHATCLI_WHATSAPP_VERIFY_TOKEN="my-verify"  # the string you chose
    export CHATCLI_WHATSAPP_ADDR=":8082"
    # export CHATCLI_WHATSAPP_PATH="/whatsapp/webhook"  # the default
    ```
  </Step>

  <Step title="Start the gateway">
    ```text theme={"system"}
    /gateway start
    /gateway status     # whatsapp should be listed
    ```
  </Step>

  <Step title="Register the webhook">
    In the app's WhatsApp configuration, set the callback URL to the public HTTPS address that reaches `CHATCLI_WHATSAPP_ADDR` and `CHATCLI_WHATSAPP_PATH`, for example `https://bot.example.com/whatsapp/webhook`, and the verify token to the same string. Meta checks it right away, so the gateway must already be running. Then subscribe the webhook to the `messages` field.
  </Step>
</Steps>

## Environment variables

| Variable | Required | Default | What it does |
| - | - | - | - |
| `CHATCLI_WHATSAPP_ACCESS_TOKEN` | yes | — | Graph API token used to download media and send replies. |
| `CHATCLI_WHATSAPP_PHONE_ID` | yes | — | Phone number ID the replies are sent from. |
| `CHATCLI_WHATSAPP_ADDR` | yes | — | Address the webhook server binds, for example `:8082`. The adapter starts only when the token, the phone ID and the address are all set. |
| `CHATCLI_WHATSAPP_APP_SECRET` | yes, in practice | — | Verifies the `X-Hub-Signature-256` on every delivery. Without it every inbound message is refused with `401`, and a warning is logged at start. |
| `CHATCLI_WHATSAPP_VERIFY_TOKEN` | yes, in practice | — | Answers Meta's webhook verification. Without it the verification is refused with `403`, and a warning is logged at start. |
| `CHATCLI_WHATSAPP_PATH` | no | `/whatsapp/webhook` | Path of the webhook. |
| `CHATCLI_WHATSAPP_HOME_CHANNEL` | no | — | Default phone number for [proactive messages](/gateway/proactive-messaging) sent with `@send whatsapp`. |

## Who can reach the bot

Deliveries without a valid signature are refused, so only Meta can feed the webhook. Past that, **anyone who messages the business number** reaches the agent, which runs with its tools and shell.

<Warning>
  There is no sender allow-list on WhatsApp. Use a number that only the intended people know, and harden the agent with [security mode](/security/overview) before exposing it.
</Warning>

## Messages

* **Handled message types**: text, audio (voice notes) and images. Video, documents, stickers, locations, reactions and interactive messages are ignored.
* **Voice**: the audio is downloaded through the Graph API and transcribed before the agent runs.
* **Images**: the image reaches the model with a default instruction to describe it; the caption you type with an image is not read, so send the question as a separate message.
* **Image replies** are uploaded to WhatsApp and sent with the reply text as the caption; on failure the text is sent alone.
* Each sender is one conversation, keyed by phone number.

## Limits

* A reply is cut at **3500 characters** and ends with `…`.
* WhatsApp only accepts free-form messages within 24 hours of the person's last message. A [proactive message](/gateway/proactive-messaging) outside that window fails, since the gateway does not send templates.
* Meta retries a delivery it did not see acknowledged in time; a retried delivery is processed again.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Meta cannot verify the callback URL">
    The gateway must be running and reachable at the URL, and `CHATCLI_WHATSAPP_VERIFY_TOKEN` must match the token typed in Meta's dashboard. With the variable unset, verification is refused with `403`.
  </Accordion>

  <Accordion title="Verified, but messages never get an answer">
    Set `CHATCLI_WHATSAPP_APP_SECRET`: without it every delivery is refused with `401`. `~/.chatcli/gateway.log` shows a "rejected an inbound delivery with no valid signature" line for each one. Also check that the webhook is subscribed to the `messages` field.
  </Accordion>
</AccordionGroup>

## See also

<CardGroup cols={2}>
  <Card title="Chat gateway" icon="comments" href="/gateway/chat-gateway">
    How messages run, voice, images, continuity and the other channels.
  </Card>

  <Card title="Proactive messaging" icon="paper-plane" href="/gateway/proactive-messaging">
    Send messages first with `@send`, within WhatsApp's 24-hour window.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.