Whatsflow Whatsflow Developers
AR Website Get an API key
From your app to a real conversation

Guide to Whatsflow API.

Connect WhatsApp to your app and send messages from one place.
Everything you need to get started, with clear examples you can adapt.

REST APIJSONAPI Key Auth
Your first steps

From zero to your first message

Start with the credentials provided when your API service is activated.

  1. 01

    Prepare your credentials

    Your service address BASE_URL, assigned SESSION name, and API_KEY.

  2. 02

    Connect your number

    Start the session, scan the QR code when prompted, and wait until its status is WORKING.

  3. 03

    Send your first message

    Try the message example with a test number you own, then add it to your app.

Service address BASE URLhttps://waha.whats-flow.netHTTPS

Use the service address above with the session name and key provided during activation. Replace default with your session name and YOUR_… and .example placeholders with your details. v2 is the documentation version; request paths start with /api. Do not add /docs/v2 or /dashboard.

Terminal · Bash / Zsh
export BASE_URL="https://waha.whats-flow.net"
export SESSION="default"
export API_KEY="YOUR_API_KEY"

Set these variables once in your terminal session before running the cURL examples. In your app, keep them in your server configuration.

Authenticated requests

One key for your requests

Include your account key in the X-Api-Key header on every request. Use a JSON body when sending messages or updating settings.

HeaderValueUsage
X-Api-KeyYOUR_API_KEYRequired for every request
Content-Typeapplication/jsonFor JSON request bodies
Acceptapplication/jsonRequest JSON responses, including the encoded QR image.
Keep your key on the server.

Make requests from your server and keep the key out of browsers and public repositories. {session} in the path and session in the request body refer to your assigned session name, not your phone number.

Request referenceAPI REFERENCE
Connection

Start a session#

Start the session provisioned by the Whatsflow team for your account. The session must already exist; this request does not create one.

POST/api/sessions/{session}/startAPI KEY

Request parameters

sessionpath · stringRequired

The session name provided during activation. Replace default with your session name.

This request does not require a body.

Replace default with the session name provided during activation. Check its status after starting: request a QR code at SCAN_QR_CODE and send messages only at WORKING.

Request · cURL
curl --request POST "${BASE_URL}/api/sessions/${SESSION}/start" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json"
Sample response (abridged)201
Response · JSON
{
    "name": "default",
    "status": "STARTING"
}
Connection

Connect a WhatsApp number#

When the session is at SCAN_QR_CODE, request the QR image and scan it from WhatsApp → Linked devices → Link a device.

GET/api/{session}/auth/qrAPI KEY

Request parameters

sessionpath · stringRequired

The session name provided during activation. Replace default with your session name.

This request does not require a body.

Send Accept: application/json to receive a Base64 image; otherwise, the response may be a binary image. Display it using data:image/png;base64, followed by the data value. This example is a placeholder, not a scannable QR code.

Request · cURL
curl --request GET "${BASE_URL}/api/${SESSION}/auth/qr" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json"
Sample response (abridged)200
Response · JSON
{
    "mimetype": "image/png",
    "data": "BASE64_QR_IMAGE_DATA"
}
Connection

Connection state#

Check status before sending. WORKING means connected, STARTING means the connection is starting, and SCAN_QR_CODE means the session is waiting for a scan.

GET/api/sessions/{session}API KEY

Request parameters

sessionpath · stringRequired

The session name provided during activation. Replace default with your session name.

This request does not require a body.

STOPPED means the session is stopped; use the start request. FAILED means the connection failed; check the phone and contact support if you need to reconnect. This response is abridged and may also include account information and config.

Request · cURL
curl --request GET "${BASE_URL}/api/sessions/${SESSION}" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json"
Sample response (abridged)200
Response · JSON
{
    "name": "default",
    "status": "WORKING"
}
Messages

Send a text message#

Send a message to a chatId. For a direct conversation, use the international phone number with digits only, followed by @c.us; for example, 201000000000@c.us.

POST/api/sendTextAPI KEY

Request parameters

sessionstringRequired

The session name assigned to your account. default is an example.

chatIdstringRequired

The chat identifier: an international number followed by @c.us for direct conversations.

textstringRequired

The text of the message to send.

linkPreviewbooleanOptional

Enable link previews in the message.

reply_tostringOptional

The ID of a previous message to reply to. Use the complete ID returned by the service.

Store the complete id to track or reply to the message. The response is abridged, and a successful request does not confirm delivery. Subscribe to message.ack for delivery and read updates when available.

Request · cURL
curl --request POST "${BASE_URL}/api/sendText" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @- <<JSON
{
    "session": "${SESSION}",
    "chatId": "201000000000@c.us",
    "text": "Hi Ahmed, your order #1042 is confirmed. Thank you for choosing us!",
    "linkPreview": false
}
JSON
Sample response (abridged)201
Response · JSON
{
    "id": "true_201000000000@c.us_EXAMPLE_MESSAGE_ID",
    "fromMe": true,
    "to": "201000000000@c.us"
}
Messages

Send an image#

Send an image with an optional caption using a direct file URL. Media sending must be enabled for your account.

POST/api/sendImageAPI KEY

Request parameters

sessionstringRequired

The session name assigned to your account. default is an example.

chatIdstringRequired

The chat identifier: an international number followed by @c.us for direct conversations.

file.urlstringRequired

A direct URL the service can download. Replace the .example address.

file.mimetypestringRequired

The MIME type matching the file, such as image/jpeg or application/pdf.

captionstringOptional

A caption or text accompanying the file.

Media sending depends on the features enabled for your account; contact the team if it is unavailable. Use a direct file URL that does not require a login, not an HTML page. Size limits depend on the service configuration.

Request · cURL
curl --request POST "${BASE_URL}/api/sendImage" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @- <<JSON
{
    "session": "${SESSION}",
    "chatId": "201000000000@c.us",
    "file": {
        "mimetype": "image/jpeg",
        "url": "https://your-store.example/products/item.jpg"
    },
    "caption": "The product you requested"
}
JSON
Sample response (abridged)201
Response · JSON
{
    "id": "true_201000000000@c.us_EXAMPLE_IMAGE_ID",
    "fromMe": true,
    "hasMedia": true
}
Messages

Send a document#

Share a PDF invoice or document from a direct URL. Set the file type and name inside file. Media sending must be enabled for your account.

POST/api/sendFileAPI KEY

Request parameters

sessionstringRequired

The session name assigned to your account. default is an example.

chatIdstringRequired

The chat identifier: an international number followed by @c.us for direct conversations.

file.urlstringRequired

A direct URL the service can download. Replace the .example address.

file.mimetypestringRequired

The MIME type matching the file, such as image/jpeg or application/pdf.

file.filenamestringOptional

The filename shown to the recipient, such as invoice-1042.pdf.

captionstringOptional

A caption or text accompanying the file.

This example uses file.url. To send the content directly, replace url with a Base64 file.data field, keeping mimetype and filename. Contact the team to confirm media availability and file limits.

Request · cURL
curl --request POST "${BASE_URL}/api/sendFile" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @- <<JSON
{
    "session": "${SESSION}",
    "chatId": "201000000000@c.us",
    "file": {
        "mimetype": "application/pdf",
        "filename": "invoice-1042.pdf",
        "url": "https://your-store.example/invoices/1042.pdf"
    },
    "caption": "Invoice for your order #1042"
}
JSON
Sample response (abridged)201
Response · JSON
{
    "id": "true_201000000000@c.us_EXAMPLE_FILE_ID",
    "fromMe": true,
    "hasMedia": true
}
Events

Receive events · Webhooks#

Set config.webhooks for the session to receive messages and connection updates on your server. First retrieve the current settings using GET /api/sessions/{session}, and preserve the other config values when updating.

PUT/api/sessions/{session}API KEY

Request parameters

sessionpath · stringRequired

The session name provided during activation. Replace default with your session name.

config.webhooksarrayRequired

The list of webhook destinations. This example uses one destination.

config.webhooks[].urlstringRequired

An HTTPS URL on your server that accepts POST requests with JSON.

config.webhooks[].eventsarrayRequired

The events to subscribe to, such as message, message.ack, and session.status.

config.webhooks[].customHeadersarrayOptional

Headers to verify incoming requests. Each entry contains name and value.

PUT replaces config and restarts a running session. This example only shows webhooks; merge your other settings before running it. On your receiver, verify X-Webhook-Secret, return 200 promptly, and use the event id to avoid processing duplicates.

Request · cURL
curl --request PUT "${BASE_URL}/api/sessions/${SESSION}" \
  --header "X-Api-Key: ${API_KEY}" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @- <<JSON
{
    "config": {
        "webhooks": [
            {
                "url": "https://your-app.example/webhooks/whatsflow",
                "events": [
                    "message",
                    "message.ack",
                    "session.status"
                ],
                "customHeaders": [
                    {
                        "name": "X-Webhook-Secret",
                        "value": "YOUR_WEBHOOK_SECRET"
                    }
                ]
            }
        ]
    }
}
JSON
Sample response (abridged)200
Response · JSON
{
    "name": "default",
    "status": "STARTING"
}

Key events

Subscription eventWhen is it sent?
messageWhen a new message arrives. For text messages, read payload.from and payload.body.
message.ackWhen a message status changes; for example, DEVICE for delivery or READ for a read receipt in payload.ackName, when available.
session.statusWhen the connection changes. Read the status from payload.status.
What does an incoming message event look like?

An abridged message event. The payload contains message data and its structure varies by event. The outer event id is separate from the message ID in payload.id.

Incoming event · JSON
{
    "id": "evt_EXAMPLE_EVENT_ID",
    "event": "message",
    "session": "default",
    "payload": {
        "id": "false_201000000000@c.us_EXAMPLE_INCOMING_ID",
        "from": "201000000000@c.us",
        "fromMe": false,
        "body": "When will my order arrive?",
        "hasMedia": false
    }
}
Build a reliable integration

Understand the response. Know your next step.

Check both the HTTP status and the error message. Error details may vary with the request and service configuration.

CodeMeaningWhat should you check?
200 / 201Successful requestRead the response. A successful send request does not confirm delivery.
400Invalid requestCheck required fields, phone number formatting, and the media type.
401Authentication failedCheck the value of the X-Api-Key header.
403Access deniedCheck that the key has access to the requested session.
404Resource not foundVerify the base URL, request path, and session name.
422Session not ready or request cannot be processedCheck the error details and session status. Sending messages requires WORKING.
501Feature unavailableContact the team to confirm that the requested feature is enabled for your account.
429Rate limit exceeded, if enabledReduce your request rate and respect Retry-After if returned.
5xxService errorCheck the connection and retain request details for support, excluding secret keys.

Manage your sending

Queue outgoing messages and respect your account limits. If a response is lost, check the result before retrying to avoid sending the same message twice.

Keep conversations welcome

Send messages to people who have agreed to hear from you, and respect opt-out requests. Use a test number before messaging customers.

Start your integration

Ready for your next step?

Contact us for API credentials or help with your integration.

Talk to the Whatsflow team