API reference

Quickstart

Send your first WhatsApp message and receive your first inbound event.

Quickstart

Send your first WhatsApp message and receive your first inbound event. Five minutes, three steps.

Before you start

You need a connected number. In the dashboard open Connections, scan the QR code with the WhatsApp account you want to send from, and wait until the connection reads connected. Copy its connection ID — a UUID you will pass with every message.

1. Create an API key

Dashboard → Developers → API keys → Create key.

The key is shown once. Store it the way you store a database password: in your secret manager, never in source control, never in front-end code. Anyone holding it can send messages as your workspace.

cap_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

If you lose it, create a new key and revoke the old one. There is no way to read an existing key back.

2. Send a message

curl -X POST https://your-domain.com/api/v1/messages \
  -H 'Authorization: Bearer cap_a1b2c3d4e5f6.xxxx…' \
  -H 'Content-Type: application/json' \
  -d '{
    "connection_id": "bbf1ba6b-be14-491c-9d9f-8d8317f1e542",
    "recipient": "+923001234567",
    "body": "Hello from MessageVia"
  }'

recipient takes a raw phone number in E.164 format. You do not need to create a contact first — an unknown number is added to your contact list automatically.

{ "data": { "id": "9bbe8e93-…", "direction": "outbound", "status": "queued", "message_type": "text", … } }

A 202 Accepted means we have taken responsibility for the message, not that WhatsApp has delivered it. See Messages for the difference, which matters more than it sounds.

3. Receive inbound messages

Replies do not come back on the same connection. They arrive as a webhook: a signed HTTPS POST to a URL you control.

Dashboard → Developers → Webhooks → Add endpoint. Give it an HTTPS URL and subscribe to message.received.

When someone messages your number, we POST:

{
  "id": "ce93fdad-1a30-4a67-a4d6-7c17e513240a",
  "type": "message.received",
  "api_version": "2026-07-20",
  "occurred_at": "2026-07-20T11:06:18+00:00",
  "data": {
    "message": {
      "id": "9bbe8e93-a33a-4221-9466-dc4847786444",
      "type": "text",
      "body": "Yes, that works",
      "attachments": []
    },
    "contact": { "id": "f57f3c61-...", "phone": "+923001234567", "name": null },
    "conversation": { "id": "e207cce6-..." },
    "connection": { "id": "bbf1ba6b-...", "name": "Support line" }
  }
}

Everything you need is in the event. You do not have to call back to find out what arrived.

Verify the signature before you trust any of it. An unverified webhook endpoint is a public API that anyone can post to. See Signature verification — it is six lines of code, and it is not optional.

No public URL yet?

While building locally, expose your machine with a tunnel:

cloudflared tunnel --url http://127.0.0.1:9099

Register the tunnel's HTTPS URL as your endpoint. We reject plain HTTP, private IP ranges and anything that resolves to a loopback or link-local address, so a tunnel is the practical way to develop against real traffic.

Once registered, use Send test event on the endpoint page to fire a synthetic message.received at your handler without waiting for a real message. Test events travel the ordinary delivery path — same envelope, same signature, same retries — and carry "test": true inside data so you can never mistake one for a customer message.

Next

  • Authentication — keys, scopes, what a rejected request looks like
  • Messages — text, media, and what "accepted" really means
  • Media — download the photos and documents customers send you
  • Webhooks — events, retries, and debugging a failing endpoint
Was this guide useful? Report an issue