WhatsApp API guide

How the WhatsApp API works, from account to webhook

The WhatsApp API works in six steps: you create an account, create a session for the number, connect it by scanning a QR code, send messages over HTTP, receive events via webhook and track whether the connection is up. Below, each step with the real call.

By D-API engineering team6 min read

The whole flow in one list

Before getting into the details, it helps to see the full path. Each item depends on the previous one, and that's the order your development team will implement it in:

  1. Account and API key. You sign up in the dashboard and copy the key. It goes in the Authorization header of every request, without the Bearer prefix.
  2. Create the session. A session is a connection to one number. You pick the sessionId and, optionally, set the webhook URL right away.
  3. Scan the QR code. The API returns the QR code, the number's owner scans it with the phone and the session becomes connected.
  4. Send. Text, media, lists and groups are POST calls with the sessionId and the destination number.
  5. Receive via webhook. Incoming messages, read receipts and state changes become requests to your URL.
  6. Monitor the connection. Your system needs to know when a number drops, so you can warn the customer before they notice on their own.

That's the design of any WhatsApp API that connects by QR code. In the examples, the base URL is https://api.d-api.cloud and every path starts with /api/v1.

Steps 1 and 2: authenticate and create the session

With the key copied from the dashboard, the first call creates the connection. The type field defines whether it's unofficial (unofficial, connected by QR code) or official (cloud_api). Here we use the unofficial one and point the webhook right away:

curl -X POST https://api.d-api.cloud/api/v1/sessions \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "customer-42",
    "type": "unofficial",
    "webhookUrl": "https://your-app.com/webhooks/whatsapp"
  }'

Pick a sessionId that already means something in your database, such as the customer or location ID. That saves you a lookup table later: when the webhook arrives, the identifier itself tells you whose event it is.

Step 3: connect the number with the QR code

The session starts out waiting for pairing. To show the QR code on your screen, fetch the ready-made image with ?image=1, which returns a PNG:

curl "https://api.d-api.cloud/api/v1/sessions/customer-42/qr?image=1" \
  -H "Authorization: YOUR_API_KEY" \
  --output qr.png

Without the parameter, the response is JSON, with the QR text, a base64 version and the time of the last update. The QR code expires within seconds and is renewed automatically, so your product's interface should fetch it again while the status is connecting. If someone would rather not use the camera, they can pair with a numeric code; the details are in connecting through the API with a QR code.

Step 4: send the first message

With the number connected, sending is a request with three required fields: sessionId, to and text. The destination uses international format, without the plus sign:

curl -X POST https://api.d-api.cloud/api/v1/messages/send/text \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "customer-42",
    "to": "14155550123",
    "text": "Your appointment tomorrow at 2 PM is confirmed."
  }'

Images, audio, video and documents follow the same pattern on their own routes, swapping text for the file field. If your system fires many sends at once, the optional async field returns a commandId immediately, and the result can be checked later without holding the request open.

In Node, the same snippet gets shorter with the official SDK, which has sessions.create, sessions.getQRCode and messages.sendText. See the Node.js SDK page.

Step 5: receive events via webhook

Everything that happens on the number reaches the configured URL as a JSON POST. The envelope is always the same: event name, sessionId, the data and a traceId to trace the message's path in your logs.

{
  "event": "messages.received",
  "sessionId": "customer-42",
  "data": {
    "id": "3EB0...",
    "type": "text",
    "fromMe": false,
    "is_group": false,
    "from_name": "Maria"
  },
  "timestamp": "2026-01-24T22:51:32.601Z",
  "traceId": "c17dee..."
}

Three things to get right in your endpoint: respond fast with status 200 and process later, in your own queue; handle the same event arriving twice without duplicating side effects; and protect the URL, since the WhatsApp webhook isn't signed. The docs recommend a secret URL and checking the sessionId. If your server fails, D-API retries up to seven times with exponential backoff. The available events and per-event configuration are in WhatsApp API webhooks.

Step 6: know when the connection drops

A number can disconnect because the owner removed the linked device, because WhatsApp ended the session, or because of instability. There are two ways to keep track:

  • Through the connection.status event: the data.status field arrives as connected, disconnected or logged_out. This is the recommended way, because the notice arrives the moment the state changes.
  • By querying the session: GET /api/v1/sessions/customer-42 returns the session data, including the status. It's useful for a diagnostics screen or to check the state after a deploy.

The difference between the two drop states matters: disconnected usually resolves with a reconnect, which the infrastructure attempts on its own, while logged_out means the number was unlinked and someone needs to scan a new QR code. When that second case happens, ideally your product shows the warning on the customer's screen, rather than them finding out because messages stopped.

Where implementations usually get stuck

The calls themselves are simple. The real work shows up at the edge of your system: storing the mapping between session and customer, building the pairing screen, processing webhooks without losing events, and deciding what to do when a number drops. Anyone who needs one connection per customer, like a SaaS, spends most of the effort there, which is why it's worth reading about the WhatsApp API for SaaS before designing the architecture.

Frequently asked questions

How long does it take to send the first message through the API?
Once you have the API key, the path is short: one call creates the session, you scan the QR code with the phone, and the next call already sends text. What usually takes longer is building the endpoint in your system that will receive the webhooks.
Does the phone need to stay on after connecting?
Not for the session to work. After pairing, the connection runs on the server as a linked device, just like WhatsApp Web. The number stays active on the phone and messages show up on both sides.
What is the sessionId?
It's the name you give each connection when you create it, for example the customer ID in your system. Every send, lookup and webhook carries this value, and that's how you know which number a message was sent from or received on.
Do I need to poll the API all the time to know if a message arrived?
No. That's what the webhook is for: D-API makes a POST to your URL for every event, such as a received message or a status change. Polling in a loop wastes resources and still arrives late.
Does the flow change if I use Meta's official API?
The connection step changes: instead of a QR code, you provide your Meta account details when creating the session with type cloud_api. After that, the send routes and the normalized webhook format are the same as for the unofficial connection.

Try D-API's WhatsApp API

3-day trial with full access. No credit card, no lock-in.