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.

:::warning 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://lora-api.agiletelecom.com/api/message-server/whatsapp/send

Phone numbers

GET https://lora-api.agiletelecom.com/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
destinationstringYesRecipient phone number in international format (e.g. +393401234567)
phoneNumberIdintegerYesSender 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
campaignIdstringNoCampaign 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
placeholdersobjectNoKey-value map to replace placeholders in the template. E.g.: {"nome": "Mario"} replaces {nome} in the message
scheduledDatestringNoScheduled send date and time. Format: yyyy-MM-dd HH:mm:ss.SSSZ (e.g. 2025-10-01 09:00:00.000+0000)
fallbackRcsobjectNoFallback configuration for the RCS channel (see Fallback section)
fallbackSmsobjectNoFallback configuration for the SMS channel. Required if fallbackRcs is present

Template object

:::tip 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.


To monitor link clicks in templates, you can use the shortLinkT1 placeholder in the placeholders field:

"placeholders": {
"shortLinkT1": "https://www.example.com/landing-page"
}

The system automatically generates a tracked short link that replaces the {shortLinkT1} placeholder in the template. This allows you to monitor how many recipients clicked the link.


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://lora-api.agiletelecom.com/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://lora-api.agiletelecom.com/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