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:
- Account and API key. You sign up in the dashboard and copy the key. It goes in the
Authorizationheader of every request, without the Bearer prefix. - Create the session. A session is a connection to one number. You pick the
sessionIdand, optionally, set the webhook URL right away. - Scan the QR code. The API returns the QR code, the number's owner scans it with the phone and the session becomes connected.
- Send. Text, media, lists and groups are POST calls with the
sessionIdand the destination number. - Receive via webhook. Incoming messages, read receipts and state changes become requests to your URL.
- 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.pngWithout 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.statusevent: thedata.statusfield arrives asconnected,disconnectedorlogged_out. This is the recommended way, because the notice arrives the moment the state changes. - By querying the session:
GET /api/v1/sessions/customer-42returns 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.
