WhatsApp API Documentation
Send messages, manage sessions, and receive webhooks using your access token. All endpoints are authenticated with your api_key.
http://sow.theheronschool.co.ke/api/v1/whatsapp
?api_key=YOUR_TOKEN
JSON
OpenAPI JSON
AI Integration
Quick start for AI systems and automation
Quick Start for AI
AI systems can integrate with this API in 3 simple steps:
- Get the OpenAPI spec: Fetch
/api-specfor complete API definition - Authenticate: Include your
api_keyas a query parameter - Make requests: Send JSON payloads to endpoints and handle responses
Example: Python
import requests # Configuration BASE_URL = "http://sow.theheronschool.co.ke/api/v1/whatsapp" API_KEY = "YOUR_ACCESS_TOKEN" # Send a message response = requests.post( f"{BASE_URL}/send", params={"api_key": API_KEY}, json={ "to": "254712345678", "message": "Hello from AI!", "type": "text" } ) # Check response if response.status_code == 200: print(response.json())
Example: JavaScript (Node.js)
const axios = require('axios'); // Configuration const BASE_URL = 'http://sow.theheronschool.co.ke/api/v1/whatsapp'; const API_KEY = 'YOUR_ACCESS_TOKEN'; // Send a message async function sendMessage(phone, message) { try { const response = await axios.post(`${BASE_URL}/send`, { to: phone, message: message, type: 'text' }, { params: { api_key: API_KEY } }); return response.data; } catch (error) { console.error('Error:', error.response?.data || error.message); } } // Usage sendMessage('254712345678', 'Hello from AI!');
AI Best Practices
- Error Handling: Always check the
successfield in responses - Rate Limiting: Implement exponential backoff for failed requests
- Phone Format: Use international format without
+prefix (e.g., 254712345678) - Session Status: Check
/statusbefore sending messages - Broadcast: Use
/broadcastfor bulk sends (max 500 recipients) - Webhooks: Register webhooks to receive real-time message events
Anti-Ban Protection
This API includes built-in anti-ban measures to protect your WhatsApp account from being banned by WhatsApp:
- Rate Limiting: Automatic hourly (20) and daily (120) message limits for unpaid users (paid plans have higher limits)
- Warm-up Period: New numbers start with reduced limits (10→120 messages over 7 days) to build trust
- Dynamic Delays: Random delays (3-10 seconds) between messages to appear more natural
- Automatic Throttling: System automatically pauses if limits are exceeded
- Usage Tracking: Real-time monitoring of message frequency and patterns
{
"success": false,
"message": "Daily limit of 120 messages exceeded",
"error": "daily_limit_exceeded",
"retry_after": 28654
}
OpenAPI Specification
Download the complete OpenAPI 3.0.0 specification for your AI system:
Authentication
How to authenticate all API requests
Every API request requires your access token (also called api_key). You can find your token on the Linked Numbers page next to each instance.
GET /api/v1/whatsapp/status?api_key=YOUR_ACCESS_TOKEN
/status
Get Instance Status
Returns the current connection state of your WhatsApp instance.
api_key
string
Yes
Your instance access token
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"state": "connected",
"status": "active",
"phone": "254700000000",
"profile_name": "John Doe"
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
Session Management
Start, stop, and sync your WhatsApp session
/start
Start Session
Starts the WhatsApp session for the given instance. Call this before sending messages if the session is disconnected.
api_key
string
Yes
Your instance access token
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/start?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"state": "initializing"
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/start?api_key=YOUR_TOKEN' \ -X POST \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/start?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/start?api_key=YOUR_TOKEN', {
method: 'POST'
});
const data = await res.json();
/sync
Sync Session State
Syncs the current session state from the engine into the database. Useful to refresh the status after reconnection.
api_key
string
Yes
Your instance access token
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/sync?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"state": "connected",
"status": "active"
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/sync?api_key=YOUR_TOKEN' \ -X POST \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/sync?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/sync?api_key=YOUR_TOKEN', {
method: 'POST'
});
const data = await res.json();
/qr
Get QR Code
Returns the QR code image (base64 PNG) to link your WhatsApp account. Add ?reset=1 to generate a fresh QR and clear any stale credentials.
api_key
string
Yes
Your instance access token
reset
boolean
No
Pass 1 to reset session and generate a fresh QR
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/qr?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"qr": "data:image\/png;base64,iVBORw0KGgo..."
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/qr?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/qr?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/qr?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
Send Messages
Send text and media messages to any WhatsApp number
+ prefix. Example: 254712345678
/send
Send Text Message
Sends a plain text WhatsApp message to the specified phone number.
api_key
string
Yes
Your instance access token (query param)
to
string
Yes
Recipient phone number in international format e.g. 254712345678
message
string
Yes
The text content of the message
type
string
No
Message type: text (default) or media
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN
{
"to": "254712345678",
"message": "Hello from the API!",
"type": "text"
}
{
"success": true,
"data": {
"id": "3EB0C767D97B42B1B6C5",
"to": "254712345678",
"timestamp": 1719230400
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN' \
-X POST \
-H 'Content-Type: application/json' \
-d '{"to":"254712345678","message":"Hello from the API!","type":"text"}' \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN', {"to":"254712345678","message":"Hello from the API!","type":"text"});
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({"to":"254712345678","message":"Hello from the API!","type":"text"})
});
const data = await res.json();
/send
Send Media Message
Sends a media message (image, document, audio) with an optional caption.
api_key
string
Yes
Your instance access token (query param)
to
string
Yes
Recipient phone number
type
string
Yes
Must be: media
message
string
No
Optional caption text
media.url
string
Yes
Publicly accessible URL to the media file
media.mimeType
string
No
MIME type e.g. image/jpeg, application/pdf
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN
{
"to": "254712345678",
"type": "media",
"message": "Check this out!",
"media": {
"url": "https:\/\/example.com\/image.jpg",
"mimeType": "image\/jpeg"
}
}
{
"success": true,
"data": {
"id": "3EB0C767D97B42B1B6C6",
"to": "254712345678"
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN' \
-X POST \
-H 'Content-Type: application/json' \
-d '{"to":"254712345678","type":"media","message":"Check this out!","media":{"url":"https://example.com/image.jpg","mimeType":"image/jpeg"}}' \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN', {"to":"254712345678","type":"media","message":"Check this out!","media":{"url":"https://example.com/image.jpg","mimeType":"image/jpeg"}});
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/send?api_key=YOUR_TOKEN', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({"to":"254712345678","type":"media","message":"Check this out!","media":{"url":"https://example.com/image.jpg","mimeType":"image/jpeg"}})
});
const data = await res.json();
Profile Info
Retrieve WhatsApp profile data for your linked number
/status
Get Profile Data
Returns full profile information including name, phone number, and profile picture URL once the instance is connected.
api_key
string
Yes
Your instance access token
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"state": "connected",
"status": "active",
"phone": "254700000000",
"profile_name": "John Doe",
"profile_picture": "https:\/\/pps.whatsapp.net\/..."
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/status?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
Webhooks
Receive real-time events on your server
Register a URL to receive POST requests whenever an event occurs on your instance (new message, connection status change, etc.).
{
"event": "message",
"instance_id": "YOUR_ENGINE_ID",
"timestamp": 1719230400,
"data": {
"from": "254712345678@s.whatsapp.net",
"body": "Hello!",
"id": "3EB0C767D97B42B1B6C5",
"timestamp": 1719230400
}
}
/webhooks
List Webhooks
Returns all registered webhook URLs for your instance.
api_key
string
Yes
Your instance access token
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN
{
"success": true,
"data": [
{
"id": 1,
"url": "https:\/\/yourapp.com\/webhook",
"events": [
"message",
"status"
],
"active": true
}
]
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
/webhooks
Register Webhook
Registers a new webhook URL to receive events from your WhatsApp instance.
api_key
string
Yes
Your instance access token (query param)
url
string
Yes
Your publicly accessible HTTPS URL
events
array
No
Array of event types: message, status, qr. Defaults to all.
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN
{
"url": "https:\/\/yourapp.com\/whatsapp-webhook",
"events": [
"message",
"status"
]
}
{
"success": true,
"data": {
"id": 2,
"url": "https:\/\/yourapp.com\/whatsapp-webhook",
"events": [
"message",
"status"
]
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN' \
-X POST \
-H 'Content-Type: application/json' \
-d '{"url":"https://yourapp.com/whatsapp-webhook","events":["message","status"]}' \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN', {"url":"https://yourapp.com/whatsapp-webhook","events":["message","status"]});
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks?api_key=YOUR_TOKEN', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({"url":"https://yourapp.com/whatsapp-webhook","events":["message","status"]})
});
const data = await res.json();
/webhooks/{id}
Delete Webhook
Removes a registered webhook by its ID.
api_key
string
Yes
Your instance access token (query param)
id
integer
Yes
Webhook ID to delete (path parameter)
DELETE http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks/{id}?api_key=YOUR_TOKEN
{
"success": true,
"message": "Webhook deleted"
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks/{id}?api_key=YOUR_TOKEN' \
-X DELETE \
$response = Http::delete('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks/{id}?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/webhooks/{id}?api_key=YOUR_TOKEN', {
method: 'DELETE'
});
const data = await res.json();
Message Logs
Retrieve sent and received message history
/messages
Get Message Logs
Returns paginated message history for your instance including sent and received messages.
api_key
string
Yes
Your instance access token
page
integer
No
Page number (default: 1)
per_page
integer
No
Results per page (default: 20, max: 100)
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/messages?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"messages": [
{
"id": 1,
"direction": "outbound",
"to": "254712345678",
"message": "Hello!",
"status": "sent",
"created_at": "2024-06-24T10:00:00Z"
}
],
"total": 42,
"page": 1
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/messages?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/messages?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/messages?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
Broadcast — Bulk Send
Send one message to many parents at once. Track delivery per recipient.
{'{name}'} in your message to personalise with each parent's name automatically.
/broadcast
Send Broadcast Message
Send a single message to multiple recipients at once. Deduplicates phone numbers automatically. Supports <?php echo e(name); ?> placeholder for personalisation. Returns per-recipient delivery results and a summary.
api_key
string
Yes
Your instance access token (query param)
message
string
Yes
Message text. Use <?php echo e(name); ?> to insert recipient name.
recipients
array
Yes
Array of recipient objects with phone (required) and name (optional). Max 500.
label
string
No
Optional label e.g. "Term 2 Fee Reminder" for your records.
type
string
No
text (default) or media
media_url
string
No
URL of media file (for type=media)
POST http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN
{
"label": "Term 2 Fee Reminder",
"message": "Dear <?php echo e(name); ?>, fees of KES 15,000 for Term 2 are due by June 30. Pay via M-Pesa: 0712345678. Thank you.",
"recipients": [
{
"phone": "254711234567",
"name": "John Kamau"
},
{
"phone": "254722345678",
"name": "Mary Wanjiku"
},
{
"phone": "254733456789",
"name": "Peter Otieno"
}
]
}
{
"success": true,
"data": {
"batch_id": 5,
"label": "Term 2 Fee Reminder",
"status": "completed",
"total": 3,
"sent": 3,
"failed": 0,
"results": [
{
"phone": "254711234567",
"name": "John Kamau",
"status": "sent"
},
{
"phone": "254722345678",
"name": "Mary Wanjiku",
"status": "sent"
},
{
"phone": "254733456789",
"name": "Peter Otieno",
"status": "sent"
}
]
},
"message": "Broadcast complete. Sent: 3, Failed: 0"
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN' \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"label": "Term 2 Fee Reminder",
"message": "Dear <?php echo e(name); ?>, fees of KES 15,000 for Term 2 are due by June 30. Pay via M-Pesa: 0712345678. Thank you.",
"recipients": [
{ "phone": "254711234567", "name": "John Kamau" },
{ "phone": "254722345678", "name": "Mary Wanjiku" },
{ "phone": "254733456789", "name": "Peter Otieno" }
]
}' \
$response = Http::post('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN', {
"label": "Term 2 Fee Reminder",
"message": "Dear <?php echo e(name); ?>, fees of KES 15,000 for Term 2 are due by June 30. Pay via M-Pesa: 0712345678. Thank you.",
"recipients": [
{ "phone": "254711234567", "name": "John Kamau" },
{ "phone": "254722345678", "name": "Mary Wanjiku" },
{ "phone": "254733456789", "name": "Peter Otieno" }
]
});
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN', {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({
"label": "Term 2 Fee Reminder",
"message": "Dear <?php echo e(name); ?>, fees of KES 15,000 for Term 2 are due by June 30. Pay via M-Pesa: 0712345678. Thank you.",
"recipients": [
{ "phone": "254711234567", "name": "John Kamau" },
{ "phone": "254722345678", "name": "Mary Wanjiku" },
{ "phone": "254733456789", "name": "Peter Otieno" }
]
})
});
const data = await res.json();
/broadcast
List Broadcasts & Stats
Returns all previous broadcasts for this instance with aggregate statistics — total messages sent, failed, and success rate.
api_key
string
Yes
Your instance access token
page
integer
No
Page number (default: 1)
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"stats": {
"total_batches": 12,
"total_sent": 847,
"total_failed": 3,
"total_recipients": 850
},
"batches": [
{
"id": 5,
"label": "Term 2 Fee Reminder",
"status": "completed",
"total": 3,
"sent": 3,
"failed": 0,
"success_rate": "100%"
}
]
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();
/broadcast/{id}
Get Broadcast Result
Retrieve the full result of a specific broadcast batch including per-recipient delivery status.
api_key
string
Yes
Your instance access token
id
integer
Yes
Batch ID returned from POST /broadcast
GET http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast/{id}?api_key=YOUR_TOKEN
{
"success": true,
"data": {
"id": 5,
"label": "Term 2 Fee Reminder",
"status": "completed",
"total": 3,
"sent": 3,
"failed": 0,
"success_rate": "100%",
"results": [
{
"phone": "254711234567",
"name": "John Kamau",
"status": "sent"
}
]
}
}
curl 'http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast/{id}?api_key=YOUR_TOKEN' \
$response = Http::get('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast/{id}?api_key=YOUR_TOKEN');
$data = $response->json();
const res = await fetch('http://sow.theheronschool.co.ke/api/v1/whatsapp/broadcast/{id}?api_key=YOUR_TOKEN', {
method: 'GET'
});
const data = await res.json();