Twasel API
A RESTful API for programmatically sending and receiving WhatsApp messages. All requests and responses use JSON over HTTPS.
Base URL
https://twasel.io/api/v1/
Protocol
HTTPS only, UTF-8
Auth Method
API Key + Secret in Headers
Daily Limit
1,000 requests/day (adjustable)
Authentication
Include the following headers with every request. Generate your key and secret from Admin Panel → API tab.
| Header | Description |
|---|---|
X-API-Key | Public key, generated from the API tab in admin panel |
X-API-Secret | Secret key, displayed only once upon creation |
Content-Type | application/json for POST requests |
Rate Limits
Each API key has a default daily limit of 1,000 requests. Exceeding it returns 429 Too Many Requests. Contact support to raise the limit.
POST /api/v1/send/text
Send a free text message to a WhatsApp number. Only works within the free reply window (24 hours from the customer's last message).
Parameters
| Field | Type | Description | |
|---|---|---|---|
to | string | Required | Recipient number in international format without + (e.g. 966501234567) |
body | string | Required | Message text, max 4,096 characters |
account_id | integer | Optional | Account ID, required only if the key is linked to multiple accounts |
Example
curl -X POST https://twasel.io/api/v1/send/text \
-H "X-API-Key: wk_abc123..." \
-H "X-API-Secret: ws_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"to": "966501234567",
"body": "مرحباً! رسالة تجريبية من تواصل."
}'import requests
resp = requests.post(
"https://twasel.io/api/v1/send/text",
headers={
"X-API-Key": "wk_abc123...",
"X-API-Secret": "ws_xyz789...",
},
json={"to": "966501234567", "body": "مرحباً من تواصل!"}
)
print(resp.json())const resp = await fetch("https://twasel.io/api/v1/send/text", {
method: "POST",
headers: {
"X-API-Key": "wk_abc123...",
"X-API-Secret": "ws_xyz789...",
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "966501234567", body: "مرحباً من تواصل!" }),
});
console.log(await resp.json());Response
{
"ok": true,
"wa_message_id": "wamid.HBgLOTY2NTAxMjM0..."
}{
"ok": false,
"error": "to_and_body_required"
}⚡ Try It
POST /api/v1/send/template
Send a Meta approved message template. Templates work even outside the free reply window. Each delivered template is billed by Meta directly.
Parameters
| Field | Type | Description | |
|---|---|---|---|
to | string | Required | Recipient number in international format without + |
template_name | string | Required | Template name exactly as registered with Meta (e.g. order_confirmation) |
language | string | Optional | Language code (default: ar) |
components | array | Optional | Template variables in Meta components format |
account_id | integer | Optional | Account ID, required only if the key is linked to multiple accounts |
Example
curl -X POST https://twasel.io/api/v1/send/template \
-H "X-API-Key: wk_abc123..." \
-H "X-API-Secret: ws_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"to": "966501234567",
"template_name": "order_confirmation",
"language": "ar",
"components": [{
"type": "body",
"parameters": [
{ "type": "text", "text": "أحمد" },
{ "type": "text", "text": "ORD-1234" }
]
}]
}'Response
{
"ok": true,
"wa_message_id": "wamid.HBgLOTY2NTAxMjM0..."
}{
"ok": false,
"error": "to_and_template_name_required"
}⚡ Try It
POST /api/v1/send/media
Send a media file (image, video, document, audio) via a direct public HTTPS URL
Parameters
| Field | Type | Description | |
|---|---|---|---|
to | string | Required | Recipient number in international format without + |
type | string | Required | image | video | document | audio |
url | string | Required | Direct public HTTPS URL to the file |
caption | string | Optional | Attached caption, max 1,024 characters |
account_id | integer | Optional | Account ID, required only if the key is linked to multiple accounts |
Example
curl -X POST https://twasel.io/api/v1/send/media \
-H "X-API-Key: wk_abc123..." \
-H "X-API-Secret: ws_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"to": "966501234567",
"type": "image",
"url": "https://example.com/product.jpg",
"caption": "منتج جديد متوفر الآن!"
}'Supported Formats & Limits
| Type | Formats | Max Size |
|---|---|---|
image | JPEG, PNG | 5 MB |
video | MP4, 3GPP | 16 MB |
document | PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX | 100 MB |
audio | AAC, MP3, MP4, AMR, OGG | 16 MB |
Response
{
"ok": true,
"wa_message_id": "wamid.HBgLOTY2NTAxMjM0..."
}{
"ok": false,
"error": "url_must_be_https"
}POST /api/v1/trigger/flow
Starts a Flow Builder flow for a specific number when an event occurs in your system. The event must match the trigger configured in the flow.
Parameters
| Field | Type | Description | |
|---|---|---|---|
event | string | Required | Event name as configured in the flow trigger |
to | string | Required | Recipient number in international format without + |
vars | object | Optional | Extra variables passed to the flow |
account_id | integer | Optional | Account ID, required only if the key is linked to multiple accounts |
Example
curl -X POST https://twasel.io/api/v1/trigger/flow \
-H "X-API-Key: wk_abc123..." \
-H "X-API-Secret: ws_xyz789..." \
-H "Content-Type: application/json" \
-d '{
"event": "order.created",
"to": "966501234567",
"vars": { "order_id": "ORD-1234" }
}'Response
{
"ok": true,
"status": "flow_started"
}{
"ok": false,
"status": "no_matching_flow"
}GET /api/v1/templates
Query approved (APPROVED) templates available for your account or a specific account
Query Parameters
| Field | Type | Description | |
|---|---|---|---|
account_id | integer | Optional | Filter by a specific account |
Response
{
"ok": true,
"templates": [
{
"id": 1,
"name": "order_confirmation",
"category": "UTILITY",
"language": "ar",
"status": "APPROVED"
},
{
"id": 2,
"name": "welcome_message",
"category": "MARKETING",
"language": "ar",
"status": "APPROVED"
}
]
}GET /api/v1/accounts
Query active WhatsApp accounts available to your key
Response
{
"ok": true,
"accounts": [
{
"id": 1,
"display_name": "الرقم الرئيسي",
"phone_number": "+966501234567",
"is_active": true
}
]
}Error Reference
On error, the response includes "ok": false with an error field describing the cause
Authentication Errors
| HTTP | error | Reason |
|---|---|---|
401 | missing_credentials | Authentication headers not included in request |
401 | invalid_key | Key not found or disabled |
401 | key_expired | Key has expired |
401 | invalid_secret | Secret does not match |
Usage Errors
| HTTP | error | Reason |
|---|---|---|
429 | rate_limit_exceeded | Daily request limit exceeded |
400 | to_and_body_required | Both to and body fields are required |
400 | to_and_template_name_required | Both to and template_name fields are required |
400 | to_type_url_required | Fields to, type, and url are required, or type is unsupported |
400 | account_id_required | Key is linked to multiple accounts, specify account_id |
400 | url_must_be_https | Media URL must use HTTPS |
422 | outside_customer_window | Free reply window expired, only templates can be sent |
403 | permission_denied | Key does not have permission for this action |
403 | invalid_account | Account does not belong to your project |
404 | unknown_endpoint | API endpoint not found |
404 | account_not_found | Account not found or disabled |
405 | method_not_allowed | HTTP method not allowed (e.g. sent GET instead of POST) |
502 | (Meta) | Error from Meta servers during message delivery |
General Notes
| Topic | Details |
|---|---|
| Free Reply Window | send/text only works within 24 hours of the customer's last inbound message. After that, use send/template. Meta bills per delivered template message. |
| Phone Format | Full international number without + or spaces, e.g. 966501234567 |
| Encoding | UTF-8. Arabic is fully supported in messages and templates |
| HTTPS Required | Unencrypted HTTP requests are rejected |
| Permissions | Each key has permissions defined by the admin. A missing permission returns 403 |