Build on a plain HTTP API
One endpoint sends text, images and documents, immediately or on a schedule. Any language that can make an HTTP request can use it — there is no SDK to install.
https://whatsapp.cubicsofts.ae/api
Authentication
Every request carries your api_key as a query or form parameter. There is no Authorization header and no token exchange.
Create an instance
Add a WhatsApp number in the dashboard.
Scan the QR code
Link the number from WhatsApp on your phone.
Copy your key
Shown once at creation. Store it somewhere safe.
/api/send
Send a text message
The default message type. Delivers a plain text WhatsApp message from your connected number.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
mobile |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Recipient in international format without a leading +, e.g. 971501234567. Local formats with a leading 0 are rejected — we cannot guess the country. |
message |
string | <span class="cs-pill cs-pill-failed">Yes</span> | The message body. |
priority |
number | <span class="cs-pill cs-pill-queued">No</span> | Queue priority, 0 (most urgent) to 300. Defaults to 10. Values of 40 and above also delay the message by that many seconds. |
reference |
string | <span class="cs-pill cs-pill-queued">No</span> | Your own identifier. Stored with the message and echoed back in every webhook for this message. |
Example request
curl -X POST 'https://whatsapp.cubicsofts.ae/api/send' \
--data-urlencode 'api_key=YOUR_API_KEY' \
--data-urlencode 'mobile=971501234567' \
--data-urlencode 'message=Your order has shipped'
<?php
$ch = curl_init('https://whatsapp.cubicsofts.ae/api/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'api_key' => 'YOUR_API_KEY',
'mobile' => '971501234567',
'message' => 'Your order has shipped',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const res = await fetch('https://whatsapp.cubicsofts.ae/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
api_key: 'YOUR_API_KEY',
mobile: '971501234567',
message: 'Your order has shipped',
}),
});
console.log(await res.json());
import requests
res = requests.post('https://whatsapp.cubicsofts.ae/api/send', data={
'api_key': 'YOUR_API_KEY',
'mobile': '971501234567',
'message': 'Your order has shipped',
})
print(res.json())
Response
{
"success": "true",
"message_id": "3f9a1c2e-7b64-4f1a-9d0e-5c8a2b41d7e3",
"totalprice": "1",
"remaincredit": "998",
"results": [
{
"status": "queued"
}
]
}
{
"success": "false",
"results": [
{
"error": "Invalid API KEY!"
}
]
}
/api/send
Send an image
Set type=1 and supply either a publicly reachable url or an uploaded file. Supported: jpg, jpeg, png, gif, webp, bmp. Maximum 3 MB.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
mobile |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Recipient number. |
type |
number | <span class="cs-pill cs-pill-failed">Yes</span> | Set to 1 for an image. |
url |
string | <span class="cs-pill cs-pill-queued">No</span> | Public URL of the image. Required unless you upload a file. |
file |
file | <span class="cs-pill cs-pill-queued">No</span> | Multipart file upload. Use instead of url. |
caption |
string | <span class="cs-pill cs-pill-queued">No</span> | Caption shown under the image. |
priority |
number | <span class="cs-pill cs-pill-queued">No</span> | Queue priority, 0–300. |
Example request
curl -X POST 'https://whatsapp.cubicsofts.ae/api/send' \
--data-urlencode 'api_key=YOUR_API_KEY' \
--data-urlencode 'mobile=971501234567' \
--data-urlencode 'type=1' \
--data-urlencode 'url=https://example.com/receipt.jpg' \
--data-urlencode 'caption=Your receipt'
<?php
$ch = curl_init('https://whatsapp.cubicsofts.ae/api/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'api_key' => 'YOUR_API_KEY',
'mobile' => '971501234567',
'type' => '1',
'url' => 'https://example.com/receipt.jpg',
'caption' => 'Your receipt',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const res = await fetch('https://whatsapp.cubicsofts.ae/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
api_key: 'YOUR_API_KEY',
mobile: '971501234567',
type: '1',
url: 'https://example.com/receipt.jpg',
caption: 'Your receipt',
}),
});
console.log(await res.json());
import requests
res = requests.post('https://whatsapp.cubicsofts.ae/api/send', data={
'api_key': 'YOUR_API_KEY',
'mobile': '971501234567',
'type': '1',
'url': 'https://example.com/receipt.jpg',
'caption': 'Your receipt',
})
print(res.json())
Response
{
"success": "true",
"message_id": "8c2d5e10-45ab-4c3f-91b7-2ea6f0c9d114",
"remaincredit": "997",
"results": [
{
"status": "queued"
}
]
}
/api/send
Send a document
Set type=2 for a document. Most common extensions are supported — pdf, docx, xlsx, csv, pptx, zip. Maximum 3 MB.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
mobile |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Recipient number. |
type |
number | <span class="cs-pill cs-pill-failed">Yes</span> | Set to 2 for a document. |
url |
string | <span class="cs-pill cs-pill-queued">No</span> | Public URL of the document. |
file |
file | <span class="cs-pill cs-pill-queued">No</span> | Multipart file upload. |
filename |
string | <span class="cs-pill cs-pill-queued">No</span> | Name the recipient sees. Defaults to the name in the URL. |
priority |
number | <span class="cs-pill cs-pill-queued">No</span> | Queue priority, 0–300. |
Example request
curl -X POST 'https://whatsapp.cubicsofts.ae/api/send' \
--data-urlencode 'api_key=YOUR_API_KEY' \
--data-urlencode 'mobile=971501234567' \
--data-urlencode 'type=2' \
--data-urlencode 'url=https://example.com/invoice-4521.pdf' \
--data-urlencode 'filename=invoice-4521.pdf'
<?php
$ch = curl_init('https://whatsapp.cubicsofts.ae/api/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'api_key' => 'YOUR_API_KEY',
'mobile' => '971501234567',
'type' => '2',
'url' => 'https://example.com/invoice-4521.pdf',
'filename' => 'invoice-4521.pdf',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const res = await fetch('https://whatsapp.cubicsofts.ae/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
api_key: 'YOUR_API_KEY',
mobile: '971501234567',
type: '2',
url: 'https://example.com/invoice-4521.pdf',
filename: 'invoice-4521.pdf',
}),
});
console.log(await res.json());
import requests
res = requests.post('https://whatsapp.cubicsofts.ae/api/send', data={
'api_key': 'YOUR_API_KEY',
'mobile': '971501234567',
'type': '2',
'url': 'https://example.com/invoice-4521.pdf',
'filename': 'invoice-4521.pdf',
})
print(res.json())
Response
{
"success": "true",
"message_id": "b1e77a3c-90d4-4a15-8f22-6c0b9e3d5a48",
"remaincredit": "996",
"results": [
{
"status": "queued"
}
]
}
/api/send
Schedule a message
Add schedule=1 and a datetime to hold the message until a specific moment. A scheduled time overrides any delay implied by priority.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
mobile |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Recipient number. |
message |
string | <span class="cs-pill cs-pill-failed">Yes</span> | The message body. |
schedule |
number | <span class="cs-pill cs-pill-failed">Yes</span> | Set to 1 to schedule. |
datetime |
string | <span class="cs-pill cs-pill-failed">Yes</span> | When to send, as YYYY-MM-DD HH:MM:SS or an ISO 8601 timestamp. Interpreted as UTC unless an offset is given. |
Example request
curl -X POST 'https://whatsapp.cubicsofts.ae/api/send' \
--data-urlencode 'api_key=YOUR_API_KEY' \
--data-urlencode 'mobile=971501234567' \
--data-urlencode 'message=Reminder: your appointment is tomorrow at 10:00' \
--data-urlencode 'schedule=1' \
--data-urlencode 'datetime=2026-09-15 09:00:00'
<?php
$ch = curl_init('https://whatsapp.cubicsofts.ae/api/send');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'api_key' => 'YOUR_API_KEY',
'mobile' => '971501234567',
'message' => 'Reminder: your appointment is tomorrow at 10:00',
'schedule' => '1',
'datetime' => '2026-09-15 09:00:00',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const res = await fetch('https://whatsapp.cubicsofts.ae/api/send', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
api_key: 'YOUR_API_KEY',
mobile: '971501234567',
message: 'Reminder: your appointment is tomorrow at 10:00',
schedule: '1',
datetime: '2026-09-15 09:00:00',
}),
});
console.log(await res.json());
import requests
res = requests.post('https://whatsapp.cubicsofts.ae/api/send', data={
'api_key': 'YOUR_API_KEY',
'mobile': '971501234567',
'message': 'Reminder: your appointment is tomorrow at 10:00',
'schedule': '1',
'datetime': '2026-09-15 09:00:00',
})
print(res.json())
Response
{
"success": "true",
"message_id": "d4c8f2a6-1b39-4e7d-a05c-83f1b6e2c907",
"results": [
{
"status": "scheduled",
"send_at": "2026-09-15T09:00:00Z"
}
]
}
/api/status
Check instance status
Returns whether your WhatsApp number is currently connected. Useful as a pre-flight check before a batch, and as a monitoring endpoint.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
Example request
curl "https://whatsapp.cubicsofts.ae/api/status?api_key=YOUR_API_KEY"
<?php
$query = http_build_query([
'api_key' => 'YOUR_API_KEY',
]);
$response = file_get_contents('https://whatsapp.cubicsofts.ae/api/status?' . $query);
echo $response;
const params = new URLSearchParams({
api_key: 'YOUR_API_KEY',
});
const res = await fetch(`https://whatsapp.cubicsofts.ae/api/status?${params}`);
console.log(await res.json());
import requests
res = requests.get('https://whatsapp.cubicsofts.ae/api/status', params={
'api_key': 'YOUR_API_KEY',
})
print(res.json())
Response
{
"success": "true",
"results": [
{
"status": "connected",
"phone_number": "971501234567",
"connected_at": "2026-08-28T11:04:22Z",
"messages_today": 42,
"daily_limit": 250
}
]
}
/api/messages
Query delivery reports
Look up the status of messages you have sent, by id or over a date range. This is the delivery report, in API form.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
api_key |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Your instance API key. Sent as a query or form parameter, not a header. |
message_id |
string | <span class="cs-pill cs-pill-queued">No</span> | Fetch one message. Omit to list. |
status |
string | <span class="cs-pill cs-pill-queued">No</span> | Filter: queued, sent, delivered, read, failed. |
from |
string | <span class="cs-pill cs-pill-queued">No</span> | Start of range, YYYY-MM-DD. |
to |
string | <span class="cs-pill cs-pill-queued">No</span> | End of range, YYYY-MM-DD. |
limit |
number | <span class="cs-pill cs-pill-queued">No</span> | Rows to return, 1–200. Default 50. |
Example request
curl "https://whatsapp.cubicsofts.ae/api/messages?api_key=YOUR_API_KEY&status=failed&limit=20"
<?php
$query = http_build_query([
'api_key' => 'YOUR_API_KEY',
'status' => 'failed',
'limit' => '20',
]);
$response = file_get_contents('https://whatsapp.cubicsofts.ae/api/messages?' . $query);
echo $response;
const params = new URLSearchParams({
api_key: 'YOUR_API_KEY',
status: 'failed',
limit: '20',
});
const res = await fetch(`https://whatsapp.cubicsofts.ae/api/messages?${params}`);
console.log(await res.json());
import requests
res = requests.get('https://whatsapp.cubicsofts.ae/api/messages', params={
'api_key': 'YOUR_API_KEY',
'status': 'failed',
'limit': '20',
})
print(res.json())
Response
{
"success": "true",
"count": 1,
"results": [
{
"message_id": "3f9a1c2e-7b64-4f1a-9d0e-5c8a2b41d7e3",
"mobile": "971501234567",
"status": "delivered",
"sent_at": "2026-08-29T08:15:02Z",
"delivered_at": "2026-08-29T08:15:04Z",
"reference": "order-4521"
}
]
}
/api/v1/integrations/orders/YOUR_SECRET
Trigger order confirmation (Next.js / Custom)
Direct REST endpoint to trigger an automated WhatsApp order confirmation from Next.js server actions, API routes, or backend systems.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
phone |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Customer mobile number (with or without international prefix). |
customerName |
string | <span class="cs-pill cs-pill-queued">No</span> | Customer full name (replaces {{customer_name}}). |
orderId |
string | <span class="cs-pill cs-pill-failed">Yes</span> | Order reference number (replaces {{order_id}}). |
orderTotal |
string | <span class="cs-pill cs-pill-queued">No</span> | Total order amount (replaces {{order_total}}). |
currency |
string | <span class="cs-pill cs-pill-queued">No</span> | Currency code, e.g. AED, USD, PKR (replaces {{currency}}). |
items |
string | <span class="cs-pill cs-pill-queued">No</span> | Summary of order items, e.g. "2x T-Shirt" (replaces {{items}}). |
storeName |
string | <span class="cs-pill cs-pill-queued">No</span> | Store display name (replaces {{store_name}}). |
shippingAddress |
string | <span class="cs-pill cs-pill-queued">No</span> | Customer shipping address (replaces {{shipping_address}}). |
Example request
curl -X POST 'https://whatsapp.cubicsofts.ae/api/v1/integrations/orders/YOUR_SECRET' \
--data-urlencode 'phone=971501234567' \
--data-urlencode 'customerName=John Doe' \
--data-urlencode 'orderId=ORD-1092' \
--data-urlencode 'orderTotal=199.00' \
--data-urlencode 'currency=AED' \
--data-urlencode 'items=1x Wireless Headphones' \
--data-urlencode 'storeName=ElectroStore' \
--data-urlencode 'shippingAddress=Downtown Dubai, UAE'
<?php
$ch = curl_init('https://whatsapp.cubicsofts.ae/api/v1/integrations/orders/YOUR_SECRET');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'phone' => '971501234567',
'customerName' => 'John Doe',
'orderId' => 'ORD-1092',
'orderTotal' => '199.00',
'currency' => 'AED',
'items' => '1x Wireless Headphones',
'storeName' => 'ElectroStore',
'shippingAddress' => 'Downtown Dubai, UAE',
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
const res = await fetch('https://whatsapp.cubicsofts.ae/api/v1/integrations/orders/YOUR_SECRET', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
phone: '971501234567',
customerName: 'John Doe',
orderId: 'ORD-1092',
orderTotal: '199.00',
currency: 'AED',
items: '1x Wireless Headphones',
storeName: 'ElectroStore',
shippingAddress: 'Downtown Dubai, UAE',
}),
});
console.log(await res.json());
import requests
res = requests.post('https://whatsapp.cubicsofts.ae/api/v1/integrations/orders/YOUR_SECRET', data={
'phone': '971501234567',
'customerName': 'John Doe',
'orderId': 'ORD-1092',
'orderTotal': '199.00',
'currency': 'AED',
'items': '1x Wireless Headphones',
'storeName': 'ElectroStore',
'shippingAddress': 'Downtown Dubai, UAE',
})
print(res.json())
Response
{
"success": true,
"status": "sent",
"orderId": "ORD-1092",
"recipient": "971501234567",
"messageUuid": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
Webhooks
Register an endpoint in the dashboard and we POST JSON to it when something happens. Failed deliveries are retried with exponential backoff.
Events
| Event | Fires when |
|---|---|
message.sent |
The message left the gateway and WhatsApp accepted it. |
message.delivered |
The recipient's device acknowledged receipt. |
message.read |
The recipient opened the chat, if read receipts are on. |
message.failed |
Delivery failed. The payload carries the reason. |
message.received |
A customer sent you a message. |
instance.connected |
Your number finished linking. |
instance.disconnected |
The session dropped. Usually transient. |
instance.qr |
A new QR code is waiting to be scanned. |
Verifying the signature
Each request carries an X-Signature header: the HMAC-SHA256 of the raw request body, keyed with your webhook secret, hex encoded. Compare it in constant time before trusting the payload.
const crypto = require('crypto');
function isValid(rawBody, headerSignature, secret) {
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(headerSignature || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Errors
Failures return the HTTP status alongside a consistent JSON envelope, so you can branch on either.
{
"success": "false",
"results": [{ "error": "Invalid API KEY!" }]
}
| Status | Message | What it means |
|---|---|---|
401 |
Invalid API KEY! | The key is wrong, revoked, or missing. |
400 |
'05012345' is not a valid international phone number. | The mobile parameter was not in international format. |
402 |
Insufficient credit. Please top up your balance. | Your balance reached zero. |
409 |
WhatsApp number is not connected. | The instance is disconnected or logged out. Re-scan the QR code. |
429 |
Daily sending limit reached for this instance. | You hit the cap that protects your number. It resets at 00:00 UTC. |
429 |
Too many requests. | You exceeded the per-key request rate. Back off and retry. |
503 |
Messaging engine unavailable. | A transient platform problem. Retry with backoff. |
Rate limits and sending caps
Two separate limits apply, and they exist for different reasons.
Request rate
Protects the platform. Exceeding it returns 429 with a Retry-After header. Back off and retry — the queue means you rarely need to burst.
Daily send cap
Protects your number. Each instance has a daily cap and a minimum gap between sends. WhatsApp bans numbers that behave like bulk senders, and that number is yours, not ours.