How-to guide

Send on WhatsApp

Reply to customers on WhatsApp from your code, inside WhatsApp's 24-hour reply window.

What you'll build

Code that answers a person who wrote to your WhatsApp business number, checks the reply window first, and handles a closed window.

How WhatsApp differs

WhatsApp only lets a business message a person freely for 24 hours after that person's last message. This is the reply window. Outside it, WhatsApp requires a pre-approved message template.

Sending templates is not available yet. Today you can reply to people while their window is open; you cannot start a conversation on WhatsApp or message someone after their window closes. A template send is refused with 422 operation_not_supported (details.reason: "template_sends_not_available").

Prerequisites

  • A secret API key with messages:send and messages:read. See Authentication and API keys.
  • A WhatsApp business number connected in the dashboard under Channels. It is a Binding, your sender on WhatsApp.
  • A conversation someone started by writing to that number. Its id comes from a message.received event (webhooks or the event stream) or from GET /v1/conversations.
  • curl, Node.js 18 or later with @voicelayer/api, or Python 3.9 or later with voicelayer.

Save the conversation id first:

export CONVERSATION_ID=<the conversation's id>

Step 1: Check the reply window

GET /v1/conversations/{id} returns the conversation. On WhatsApp it has a window: open says whether you may reply, and closesAt says until when.

curl "https://api.vlayers.ai/v1/conversations/$CONVERSATION_ID" \
  -H "Authorization: Bearer $VOICELAYER_API_KEY"
{
  "conversation": {
    "id": "0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21",
    "channel": "whatsapp",
    "controller": "api",
    "window": { "open": true, "closesAt": "2026-10-21T15:04:05.000Z" }
  }
}

Step 2: Reply in the conversation

POST /v1/conversations/{id}/messages sends into the conversation. The channel, your WhatsApp number and the person come from the conversation.

curl -X POST "https://api.vlayers.ai/v1/conversations/$CONVERSATION_ID/messages" \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": {
      "type": "text",
      "text": "Yes, we have a table at 7pm. Shall I book it?"
    }
  }'
Response · 202
{
  "message": {
    "id": "0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32",
    "conversationId": "0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21",
    "channel": "sms",
    "direction": "outbound",
    "status": "queued",
    "text": "Yes, we have a table at 7pm. Shall I book it?",
    "media": [],
    "from": "+14155550100",
    "to": "+15550123",
    "bindingId": null,
    "metadata": {},
    "error": null,
    "createdAt": "2026-10-20T15:04:05.000Z",
    "parts": [
      {
        "id": "0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32",
        "status": "queued"
      }
    ]
  }
}

A long text is sent as several messages (up to 4,096 characters each).

Step 3: Handle a closed window

If the window has closed, the reply is refused with 409 window_closed and nothing is sent. Wait for the person to write again: their next message reopens the window for another 24 hours. Tell your users or your agent to ask for what they need while the window is open.

Test it

In test mode, a reserved number plays the customer. Without a connected WhatsApp number, your free test sender receives it, but it has no reply window, so Step 1 shows no window. To test the 24-hour window itself, connect your WhatsApp number and name it in to:

curl -X POST https://api.vlayers.ai/v1/test/inbound \
  -H "Authorization: Bearer $VOICELAYER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "whatsapp",
    "from": "+15550124",
    "text": "Hi, can I change my delivery address?"
  }'

Save the returned conversationId as CONVERSATION_ID and run Steps 1 and 2. The reply goes to a simulated carrier and costs nothing. See Test mode.

Templates you have

GET /v1/channels/whatsapp/templates lists the templates Meta approved for a WhatsApp number, with their variables. It is read only for now; use it to prepare for template sends.

curl "https://api.vlayers.ai/v1/channels/whatsapp/templates?bindingId=$BINDING_ID" \
  -H "Authorization: Bearer $VOICELAYER_API_KEY"

Common errors

ErrorStatusHow to fix
window_closed409Wait for the person to write again. Template sends, the way to reach someone outside the window, are not available yet (operation_not_supported).
operation_not_supported422Send text instead (inside the conversation's window, on windowed channels).
capability_not_ready409Fix the connection in the dashboard (Channels) using details.remediation when present, then send again.
no_sender409Connect a sender for the channel in the dashboard (for email, create a mailbox), or name one in from.
not_found404Check the id, and that the key belongs to the workspace (and covers the channel) that owns it.
recipient_not_allowed403Reply in an existing conversation instead, or wait for the person to write first.

Next steps

On this page