Skip to main content

WhatsApp API

What is WhatsApp Business API​

WhatsApp Business API allows you to send messages through Meta's WhatsApp Business platform via the Qlara APIs. It is the most widely used messaging channel in the world, with high open and engagement rates.

Messages can be sent in two modes:

  • Template: messages based on Meta-approved templates. They can be sent at any time, without time restrictions. Ideal for notifications, marketing, and proactive communications.
  • Free-form message (body): custom content (text, images, documents, etc.). Only usable within the 24-hour window from the last message received from the user.
24-Hour Window

Free-form messages (body) can only be sent within 24 hours of the last message received from the user. After this period, you must use a Meta-approved template. Messages sent outside the window will be rejected.

The system supports an automatic fallback chain: if WhatsApp cannot deliver the message, the system tries RCS and finally SMS.


Endpoint​

Sending messages​

POST https://api.qlara.ai/api/message-server/whatsapp/send

Phone numbers​

GET https://api.qlara.ai/api/message-server/whatsapp/phone-numbers

Content-Type: application/json

Authentication: API Key (X-Api-Key) or Basic Auth (Authorization: Basic)


Send request fields​

FieldTypeRequiredDefaultDescription
destinationstringYes–Recipient phone number in international format (e.g. +393401234567)
phoneNumberIdintegerYes–Sender WhatsApp Business number ID (obtained from Get All Phone Numbers)
templateobjectYes*–Reference to a Meta-approved template. *Mutually exclusive with body
bodyobjectYes*–Free-form message content. *Mutually exclusive with template
campaignIdstringNo–Campaign identifier to group multiple messages. Maximum 255 characters
messageIdstringNo(auto)Custom message identifier. If not provided, it is automatically generated (UUID)
simulationbooleanNofalseIf true, the message is processed but not physically sent. Useful for testing
enableNotificationbooleanNotrueIf true, enables delivery and read notifications to your callback URL
placeholdersobjectNo–Key-value map to replace placeholders in the template. E.g.: {"nome": "Mario"} replaces {nome} in the message
scheduledDatestringNo–Scheduled send date and time. Format: yyyy-MM-dd HH:mm:ss.SSSZ (e.g. 2025-10-01 09:00:00.000+0000)
fallbackRcsobjectNo–Fallback configuration for the RCS channel (see Fallback section)
fallbackSmsobjectNo–Fallback configuration for the SMS channel. Required if fallbackRcs is present

Template object​

Template pre-approval

Templates must be approved by Meta before use. Plan ahead: the approval process can take up to 24 hours. Check the status of your templates in the Qlara platform.

Used to send a message based on a Meta-approved template.

FieldTypeRequiredDescription
idintegerYesTemplate ID in the system (obtained from Get All Templates)
mediaUrlstringNoMedia URL to insert in the template header (if the template includes a header with an image or video)

WhatsApp Template Preview


Body object​

Used to send a free-form message. Must contain one and only one of the following sub-objects. Free-form messages can only be sent within the 24-hour window from the last message received from the user.

body > text​

Simple text message.

FieldTypeRequiredDescription
bodystringYesMessage text

WhatsApp Text Preview

body > image​

Image with optional caption.

FieldTypeRequiredDescription
urlstringYes*Public image URL. *Mutually exclusive with key
keystringYes*Media key on internal storage. *Mutually exclusive with url
captionstringNoCaption displayed below the image

body > video​

Video with optional caption.

FieldTypeRequiredDescription
urlstringYes*Public video URL. *Mutually exclusive with key
keystringYes*Internal media key. *Mutually exclusive with url
captionstringNoCaption

body > audio​

Audio message.

FieldTypeRequiredDescription
urlstringYes*Public audio URL. *Mutually exclusive with key
keystringYes*Internal media key. *Mutually exclusive with url

body > document​

Document (PDF, DOC, etc.) with optional filename and caption.

FieldTypeRequiredDescription
urlstringYes*Public document URL. *Mutually exclusive with key
keystringYes*Internal media key. *Mutually exclusive with url
filenamestringNoFilename shown to the recipient (e.g. fattura_marzo.pdf)
captionstringNoCaption

WhatsApp Document Preview

body > sticker​

Sticker in WebP format.

FieldTypeRequiredDescription
urlstringYes*Public sticker URL (WebP format). *Mutually exclusive with key
keystringYes*Internal media key. *Mutually exclusive with url

body > location​

Geographic location displayed on a map.

FieldTypeRequiredDescription
latitudestringYesLatitude (e.g. "45.4642")
longitudestringYesLongitude (e.g. "9.1900")
namestringNoLocation name (e.g. "Negozio Milano Centro")
addressstringNoText address (e.g. "Via Roma 1, 20121 Milano")

body > reaction​

Emoji reaction to an existing message.

FieldTypeRequiredDescription
messageIdstringYesID of the message to react to
emojistringYesReaction emoji

Fallback chain​

The system supports sending with an automatic fallback chain:

WhatsApp → RCS → SMS

If WhatsApp cannot deliver the message, the system tries RCS (if configured) and finally SMS.

fallbackRcs object​

FieldTypeRequiredDescription
agentIdintegerYesSender RCS agent ID
templateIdintegerYes*RCS template ID. *Mutually exclusive with body
typestringNoRCS body type: TEXT, CARD, CAROUSEL (required if using body)
bodyobjectYes*Inline RCS body. *Mutually exclusive with templateId

fallbackSms object​

FieldTypeRequiredDescription
senderstringYesSMS sender (alphanumeric or numeric)
textstringYesFallback SMS text

Rule: If fallbackRcs is present, fallbackSms is required. You can configure only fallbackSms without fallbackRcs for a direct WhatsApp -> SMS fallback.

Full request example​

POST /api/message-server/whatsapp/send — with RCS + SMS fallback
{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"name": "Mario"
},
"fallbackRcs": {
"agentId": 10,
"templateId": 99
},
"fallbackSms": {
"sender": "MyCompany",
"text": "Hi Mario! We have a message for you."
}
}

WhatsApp → SMS only chain (no RCS):

POST /api/message-server/whatsapp/send — WhatsApp → SMS fallback
{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"fallbackSms": {
"sender": "MyCompany",
"text": "Hi! Visit https://example.com"
}
}

WhatsApp templates support two tracking modes, body placeholder and button URL tracking. Click data is available in the campaign stats and exported delivery reports.

Body placeholder (shortLinkT1)​

Insert the {shortLinkT1} placeholder anywhere in the template body, then pass the destination URL in the placeholders map at send time:

Send request — tracked link in body
{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"shortLinkT1": "https://www.example.com/landing-page"
}
}

The platform replaces {shortLinkT1} with a short, trackable URL pointing to your landing page.

When creating a template with a URL button, set trackButtonLinks: true to wrap every button URL in a trackable short link automatically — no placeholder required.

Template creation — tracked button URLs
{
"name": "marketing_welcome",
"lang": "en",
"category": "MARKETING",
"body": "Hi {{1}}, welcome to our service!",
"buttons": [
{
"type": "URL",
"text": "Open dashboard",
"url": "https://app.example.com/welcome"
}
],
"trackButtonLinks": true
}

Note: shortLinkT1 and trackButtonLinks are independent — you can use either, both, or neither in the same template.


Response​

Response
{
"messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": null,
"sms": null
}
}
FieldTypeDescription
messageIdstringUnique message ID. Use it to correlate delivery notifications
simulationbooleantrue if the message was in simulation mode
results.whatsapp.acceptedbooleantrue if WhatsApp accepted the message
results.rcsobject/nullRCS fallback result (if configured, otherwise null)
results.smsobject/nullSMS fallback result (if configured, otherwise null)

Important: accepted: true means the message was accepted for sending, not that it was delivered. Delivery confirmation arrives via callback.


Notifications (Callback)​

Delivery Notification​

Message delivery notification:

{
"channel": "WHATSAPP",
"eventType": "DELIVERY",
"messageId": "88116e2f-b8b4-40fe-b727-f453b6b99adc",
"destination": "+393409997528",
"statusCode": 3,
"description": "delivered",
"eventDate": "2025-10-16T10:42:18Z"
}
statusCodeMeaning
3Message delivered
6Message undeliverable

Read Notification​

Read notification (the recipient opened the message):

{
"channel": "WHATSAPP",
"eventType": "READ",
"messageId": "88116e2f-b8b4-40fe-b727-f453b6b99adc",
"destination": "+393409997528",
"eventDate": "2025-10-16T10:42:18Z"
}

Inbound Text Message​

Notification when the user replies with a text message:

{
"channel": "WHATSAPP",
"eventType": "INBOUND",
"messageId": "wamid.HBxxxxxxxxxxxxxxxxx",
"source": "+393471488489",
"destination": "+393209998877",
"receivedDate": "2025-10-31T10:59:05.099Z",
"messageType": "TEXT",
"text": "Messaggio di risposta dell'utente"
}

Inbound Media Message​

Notification when the user sends an image, audio, or video. The mediaKey field contains the key to download the file.

{
"channel": "WHATSAPP",
"eventType": "INBOUND",
"source": "+393471488489",
"destination": "+393209998877",
"receivedDate": "2025-10-31T11:00:41.003Z",
"messageType": "IMAGE",
"mediaKey": "b394ab72/efd4987c/39b4879f6fed01f0d622453be1488c93"
}

Phone Numbers​

To get the list of WhatsApp Business numbers associated with your account:

GET https://api.qlara.ai/api/message-server/whatsapp/phone-numbers

From the response, take the id field value of the number you want to use as the sender: this will be the phoneNumberId to include in send requests.

To get the details of a single number:

GET https://api.qlara.ai/api/message-server/whatsapp/phone-numbers/{id}

Examples​

1. Sending with a template​

Sending a message based on an approved template, with placeholders and media in the header:

Sending with template
{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42,
"mediaUrl": "https://example.com/images/promo.jpg"
},
"placeholders": {
"nome": "Mario",
"codiceSconto": "SPRING25"
},
"enableNotification": true
}

2. Sending a text message​

Sending a free-form text message (requires an open 24h window):

Free-form text message
{
"destination": "+393401234567",
"phoneNumberId": 5,
"body": {
"text": {
"body": "Ciao Mario! Grazie per averci contattato. Il tuo ordine è in fase di preparazione."
}
}
}

3. Sending an image​

Sending an image with a caption:

{
"destination": "+393401234567",
"phoneNumberId": 5,
"body": {
"image": {
"url": "https://example.com/images/ricevuta-ordine.jpg",
"caption": "Ecco la ricevuta del tuo ordine #12345"
}
}
}

4. Sending a document​

Sending a PDF document with a custom filename:

{
"destination": "+393401234567",
"phoneNumberId": 5,
"body": {
"document": {
"url": "https://example.com/docs/fattura-marzo-2025.pdf",
"filename": "Fattura_Marzo_2025.pdf",
"caption": "In allegato la fattura di marzo 2025"
}
},
"campaignId": "fatture-marzo-2025"
}

5. Sending with RCS + SMS fallback​

Sending with a complete fallback chain: WhatsApp -> RCS -> SMS. If WhatsApp fails to deliver, the system tries RCS; if RCS also fails, it sends an SMS.

Fallback WhatsApp -> RCS -> SMS
{
"destination": "+393401234567",
"phoneNumberId": 5,
"template": {
"id": 42
},
"placeholders": {
"nome": "Mario"
},
"enableNotification": true,
"fallbackRcs": {
"agentId": 1,
"templateId": 10
},
"fallbackSms": {
"sender": "MyBrand",
"text": "Ciao Mario, abbiamo una promozione per te! Visita il nostro sito per i dettagli."
}
}

Response (with fallback activated):

{
"messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c",
"simulation": false,
"results": {
"whatsapp": {
"accepted": true
},
"rcs": {
"accepted": true,
"reasons": []
},
"sms": {
"accepted": true,
"unicode": false,
"parts": 1,
"reasons": []
}
}
}

Error codes​

HTTP CodeMeaningWhat to do
200Request processedCheck results.whatsapp.accepted to verify acceptance
400Bad requestVerify required fields (destination, phoneNumberId, body or template)
401UnauthenticatedVerify your API Key or Basic Auth credentials
403Access deniedIP not whitelisted or unauthorized resource
404Not foundTemplate or number does not exist
422Unprocessable entityData is syntactically correct but semantically invalid (e.g. unapproved template)
429Too many requestsYou have exceeded the rate limit. Retry after the indicated period
500Internal server errorRetry later. If the problem persists, contact support