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

# Receiving Messages

> Handle incoming messages with webhooks, or read stored chats and messages from GOWA's chat storage.

GOWA offers two ways to receive messages:

| Method | Use it for |
| - | - |
| **Webhooks** (recommended) | Reacting to events in real time. GOWA pushes each event to your URL. |
| **Chat storage API** | Reading history, catching up after downtime, building inbox views. |

## Webhooks

Start GOWA with a webhook URL and secret:

```bash theme={null}
./whatsapp rest --basic-auth=admin:changeme \
  --webhook=https://example.com/wa-hook \
  --webhook-secret=change-me \
  --webhook-events=message,message.ack
```

A text message arrives as:

```json theme={null}
{
  "event": "message",
  "device_id": "628123456789@s.whatsapp.net",
  "session_id": "my-device",
  "payload": {
    "id": "3EB0C127D7BACC83D6A1",
    "chat_id": "628987654321@s.whatsapp.net",
    "from": "628987654321@s.whatsapp.net",
    "from_name": "John Doe",
    "timestamp": "2026-10-15T10:30:00Z",
    "is_from_me": false,
    "body": "Hello, how are you?"
  }
}
```

In a group, `chat_id` is the group JID (`...@g.us`) and `from` is the member who sent it.

### Example: auto-reply bot

Verify the signature, acknowledge, then reply through the API with the same device:

```javascript theme={null}
const express = require("express");
const crypto = require("crypto");

const GOWA = "http://localhost:3000";
const AUTH = "Basic " + Buffer.from("admin:changeme").toString("base64");
const SECRET = "change-me";

const app = express();
app.post("/wa-hook", express.raw({ type: "application/json" }), async (req, res) => {
  const sig = crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
  if (req.get("X-Hub-Signature-256") !== `sha256=${sig}`) return res.sendStatus(401);
  res.sendStatus(200);

  const evt = JSON.parse(req.body);
  if (evt.event !== "message" || evt.payload.is_from_me) return;
  if (!/^hi\b/i.test(evt.payload.body || "")) return;

  await fetch(`${GOWA}/send/message`, {
    method: "POST",
    headers: {
      Authorization: AUTH,
      "Content-Type": "application/json",
      "X-Device-Id": evt.session_id,          // reply from the slot that received it
    },
    body: JSON.stringify({
      phone: evt.payload.chat_id,
      message: "Hello! How can we help?",
      reply_message_id: evt.payload.id,
    }),
  });
});
app.listen(8080);
```

For a fixed reply to every message, `WHATSAPP_AUTO_REPLY="We'll get back to you soon"` does this without any code.

See [Webhooks](https://gowa-docs.mintlify.site/concepts/webhooks.md) for every event type, media fields, retries and per-device URLs.

## Chat storage API

GOWA records chats and messages for each slot in its local chat storage. Query it per device:

```bash theme={null}
# list chats (filters: search, has_media, archived; paging: limit, offset)
curl -u admin:changeme -H "X-Device-Id: my-device" \
  "http://localhost:3000/chats?limit=20"

# messages in one chat (filters: start_time, end_time, media_only, is_from_me, search)
curl -u admin:changeme -H "X-Device-Id: my-device" \
  "http://localhost:3000/chat/628987654321@s.whatsapp.net/messages?limit=50"
```

Only messages GOWA has seen (received while connected, or delivered by WhatsApp's history sync) are available. To ask the phone for older history in a chat, call `POST /chat/{chat_jid}/history` with `{"count": 50}`; the messages arrive asynchronously.

Polling is suitable for catch-up and inbox views. For bots and automations, use webhooks.

## Downloading media

With auto-download on (default), the webhook gives a path under `statics/media/`, served at `http://localhost:3000/statics/media/<file>`. Otherwise fetch the media on demand:

```bash theme={null}
curl -u admin:changeme -H "X-Device-Id: my-device" \
  "http://localhost:3000/message/3EB0C127D7BACC83D6A3/download?phone=628987654321@s.whatsapp.net"
```

## Read receipts

Mark a message read (blue ticks) with `POST /message/{message_id}/read` and `{"phone": "<chat_jid>"}`, or set `WHATSAPP_AUTO_MARK_READ=true` to mark every incoming message read automatically.


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