WhatsApp Business API
The WhatsApp Business API through Qlara enables you to send messages to customers at scale with reliable delivery and rich media support. Leverage WhatsApp's massive user base to reach your audience with templates, notifications, and personalized communication.
Overview
WhatsApp integration via Qlara provides two distinct sending modes:
- Template-based messaging: Send pre-approved templates anytime without time restrictions
- Free-form messaging: Send custom messages within a 24-hour window after customer engagement
The API supports rich media including text, images, videos, audio files, documents, stickers, locations, and emoji reactions. With configurable fallback chains (WhatsApp → RCS → SMS), you can ensure your messages reach customers even if WhatsApp isn't available.
Authentication
All WhatsApp API requests require authentication using your API key. Include the API key in the X-Api-Key header:
X-Api-Key: your_api_key_here
Sending Messages
Send Endpoint
POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
destination | string | Yes | Recipient phone number in international format (e.g., +39XXXXXXXXXX) |
phoneNumberId | string | Yes | Your WhatsApp Business phone number ID |
template | object | Conditional | Template object for approved messages (required if body is not provided) |
body | string | Conditional | Free-form message text (required if template is not provided; only valid within 24h of customer engagement) |
media | object | No | Media content (image, video, audio, document, sticker, location) |
fallbackRcs | boolean | No | Enable RCS fallback (default: false) |
fallbackSms | boolean | No | Enable SMS fallback (default: false) |
Template Object
\{
"name": "template_name",
"language": "en",
"parameters": [
"value1",
"value2"
]
\}
Media Types
WhatsApp supports the following media types in your messages:
- text: Plain text messages
- image: JPEG and PNG images
- video: MP4 and 3GPP video files
- audio: MP3, OGG, and WAV audio files
- document: PDF and Office documents
- sticker: Animated and static WebP stickers
- location: Coordinates with optional label
- emoji reactions: React to messages with emoji
Fallback Chain
Configure fallback messaging to ensure delivery when WhatsApp is unavailable:
\{
"destination": "+39XXXXXXXXXX",
"phoneNumberId": "your_phone_id",
"body": "Your message",
"fallbackRcs": true,
"fallbackSms": true
\}
If WhatsApp delivery fails:
- Message attempts delivery via RCS (if
fallbackRcsis enabled) - If RCS unavailable, falls back to SMS (if
fallbackSmsis enabled)
Managing Phone Numbers
Get Phone Numbers Endpoint
GET https://lora-api.agiletelecom.com/api/message-server/whatsapp/phone-numbers
Retrieve all registered WhatsApp Business phone numbers associated with your account.
Response
\{
"phoneNumbers": [
\{
"id": "phone_number_id",
"phoneNumber": "+39XXXXXXXXXX",
"displayName": "Your Business Name",
"status": "CONNECTED"
\}
]
\}
Response Format
Successful send requests return:
\{
"messageId": "wamid.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"simulation": false,
"results": [
\{
"destination": "+39XXXXXXXXXX",
"accepted": true
\}
]
\}
| Field | Type | Description |
|---|---|---|
messageId | string | Unique identifier for this message |
simulation | boolean | Indicates if this was a test/simulation send |
results | array | Array of per-destination results |
accepted | boolean | Whether the destination accepted the message |
Templates
Template Management
WhatsApp requires message templates to be approved by Meta before sending. Templates ensure quality and prevent spam.
Template Approval Process
- Submit template for review through the API
- Meta reviews templates within 24 hours
- Once approved, use template name in send requests
- You can modify approved templates (requires new approval)
CRUD Operations
Use the following endpoints for template management:
- Create: POST
/api/message-server/whatsapp/templates - List: GET
/api/message-server/whatsapp/templates - Get: GET
/api/message-server/whatsapp/templates/{id} - Update: PUT
/api/message-server/whatsapp/templates/{id} - Delete: DELETE
/api/message-server/whatsapp/templates/{id}
Tracked Links
Use the shortLinkT1 placeholder in your messages to automatically generate short, tracked links:
Your message text with \{shortLinkT1\} placeholder
This enables analytics and click tracking for your campaigns.
Code Examples
- cURL
- Python
- Node.js
- PHP
- Java
- C#
- Go
- Ruby
curl -X POST https://lora-api.agiletelecom.com/api/message-server/whatsapp/send \
-H "X-Api-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '\{
"destination": "+39XXXXXXXXXX",
"phoneNumberId": "your_phone_id",
"body": "Hello from Qlara!"
\}'
import requests
api_key = "your_api_key"
url = "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send"
payload = \{
"destination": "+39XXXXXXXXXX",
"phoneNumberId": "your_phone_id",
"body": "Hello from Qlara!"
\}
headers = \{
"X-Api-Key": api_key,
"Content-Type": "application/json"
\}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
const fetch = require('node-fetch');
const apiKey = 'your_api_key';
const url = 'https://lora-api.agiletelecom.com/api/message-server/whatsapp/send';
const payload = \{
destination: '+39XXXXXXXXXX',
phoneNumberId: 'your_phone_id',
body: 'Hello from Qlara!'
\};
const options = \{
method: 'POST',
headers: \{
'X-Api-Key': apiKey,
'Content-Type': 'application/json'
\},
body: JSON.stringify(payload)
\};
fetch(url, options)
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
<?php
$apiKey = 'your_api_key';
$url = 'https://lora-api.agiletelecom.com/api/message-server/whatsapp/send';
$payload = [
'destination' => '+39XXXXXXXXXX',
'phoneNumberId' => 'your_phone_id',
'body' => 'Hello from Qlara!'
];
$options = [
'http' => [
'header' => "X-Api-Key: $apiKey\r\nContent-Type: application/json\r\n",
'method' => 'POST',
'content' => json_encode($payload)
]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
echo $response;
?>
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class WhatsAppExample \{
public static void main(String[] args) throws Exception \{
String apiKey = "your_api_key";
String url = "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send";
String json = "\{\\"destination\\": \\"+39XXXXXXXXXX\\", \\"phoneNumberId\\": \\"your_phone_id\\", \\"body\\": \\"Hello from Qlara!\\"\}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("X-Api-Key", apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
\}
\}
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program \{
static async Task Main() \{
var apiKey = "your_api_key";
var url = "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send";
var payload = new \{
destination = "+39XXXXXXXXXX",
phoneNumberId = "your_phone_id",
body = "Hello from Qlara!"
\};
var json = System.Text.Json.JsonSerializer.Serialize(payload);
using (var client = new HttpClient()) \{
client.DefaultRequestHeaders.Add("X-Api-Key", apiKey);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
\}
\}
\}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() \{
apiKey := "your_api_key"
url := "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send"
payload := map[string]string\{
"destination": "+39XXXXXXXXXX",
"phoneNumberId": "your_phone_id",
"body": "Hello from Qlara!",
\}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("X-Api-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client\{\}
resp, _ := client.Do(req)
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
\}
require 'net/http'
require 'json'
require 'uri'
api_key = 'your_api_key'
url = URI('https://lora-api.agiletelecom.com/api/message-server/whatsapp/send')
payload = \{
destination: '+39XXXXXXXXXX',
phoneNumberId: 'your_phone_id',
body: 'Hello from Qlara!'
\}
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request['X-Api-Key'] = api_key
request['Content-Type'] = 'application/json'
request.body = payload.to_json
response = http.request(request)
puts response.body
Webhooks & Delivery
Delivery Status
Monitor message delivery through webhooks configured in your account settings.
Status Codes
| Code | Status | Description |
|---|---|---|
3 | Delivered | Message successfully delivered to WhatsApp servers |
6 | Undeliverable | Message could not be delivered to recipient |
Webhook Payloads
Your callback URL receives delivery confirmations with detailed status information:
\{
"messageId": "wamid.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"destination": "+39XXXXXXXXXX",
"status": 3,
"timestamp": "2024-01-15T10:30:45Z"
\}
Best Practices
- Use templates for time-sensitive and promotional messages to ensure consistent approval and anytime sending
- Leverage fallback chains to maximize delivery rates across channels
- Monitor webhook callbacks to track message delivery in real-time
- Test templates during development to ensure proper variable substitution
- Keep phone numbers accurate and up-to-date in your system
- Use tracked links for campaign analytics and performance measurement
- Respect the 24-hour message window for free-form messages after customer interaction