CLEANHOSTBULKSEND API
Connect your WhatsApp number once, then use these endpoints from your own website or backend to manage clients, send them notifications, and get notified the moment they reply.
What you can build with this
| Client control panel | Pull your connected numbers, conversation history, and group lists into your own dashboard. |
| Admin notifications | Register a webhook so your site is notified the instant a client messages you back — no polling required. |
| Client notifications | Send order updates, reminders, and confirmations to clients from your own app. |
Authentication
Every request to the API is authenticated with your account's API key, sent as a bearer token:
Authorization: Bearer YOUR_API_KEY
Find your key under API key in your dashboard once logged in. Treat it like a password — anyone holding it can send messages from your connected numbers. If it ever leaks, regenerate it immediately from that same page; the old key stops working the moment you do.
Content-Type: application/json on any POST request with a body.Connecting a number
Before the API can send or receive anything, a WhatsApp number needs to be connected once from your dashboard (Numbers → Connect a number → scan the QR code from the WhatsApp app on that phone). This is a one-time step per number; the API itself doesn't create connections, only uses ones that are already active.
Each connected number is called an instance and has a numeric instance_id you'll pass to most endpoints below.
Webhooks — getting notified as admin
To be notified whenever a client replies (instead of continuously checking for new messages), set a webhook URL for each number under Webhook settings in your dashboard. We'll POST to that URL in real time whenever a message arrives:
{
"instance_id": 1,
"from": "254712345678",
"type": "text",
"content": "Hi, is this still available?",
"wa_message_id": "ABCD1234",
"timestamp": "2026-07-11T10:15:00Z"
}
Your endpoint should respond quickly with a 2xx status. Delivery is best-effort — if your endpoint is briefly down, it won't affect your WhatsApp connection, but retries aren't currently queued, so keep it reliable and fast.
List your numbers
GET/api/v1/instances.php
Returns every WhatsApp number on your account, so you can build a client-facing or internal picker for "which number should this notification send from."
curl /api/v1/instances.php \ -H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": [
{ "id": 1, "label": "Sales line", "phone_number": "254712345678", "status": "connected", "created_at": "2026-06-01 09:00:00" }
]
}
Conversation history
GET/api/v1/messages.php?instance_id=1&limit=50
Returns recent messages (both directions) for one of your numbers — useful for showing a client's conversation thread inside your own admin panel.
| Param | Required | Notes |
|---|---|---|
instance_id | Yes | Must belong to your account. |
limit | No | 1–200, default 50. |
List groups
GET/api/v1/groups.php?instance_id=1
Returns the WhatsApp groups a number belongs to. Add &sync=1 to force a fresh pull straight from WhatsApp first (a little slower, but up to date) instead of the last cached copy.
Send a message
POST/api/v1/send-message.php
Send a single notification to one client — order confirmations, appointment reminders, support replies, anything triggered by an event on your own site.
curl -X POST /api/v1/send-message.php \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"instance_id": 1,
"to": "254712345678",
"text": "Hi Jane, your order #4021 has shipped!"
}'
| Field | Type | Required | Notes |
|---|---|---|---|
instance_id | number | Yes | Which connected number sends this. |
to | string | Yes | Client's phone number. |
text | string | Yes | Message body. |
{ "success": true, "wa_message_id": "ABCD1234" }
Send to many clients
POST/api/v1/send-bulk.php
Send the same notification to a list of clients at once — a promo, a service update, a reminder batch. Messages are queued and delivered gradually rather than sent all at once in the same request; check conversation history or your dashboard's Messages page to see each one's delivery status as it goes out.
curl -X POST /api/v1/send-bulk.php \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"instance_id": 1,
"numbers": ["254712345678", "0798765432"],
"text": "Reminder: your appointment is tomorrow at 10am."
}'
{ "success": true, "queued": 2 }
Delivery & status
Every message you send is recorded against the instance it went out on. Poll /api/v1/messages.php for an instance to see each message's current status, or view the same thing under Messages in your dashboard.
Errors
Errors return a non-2xx status code with a JSON body:
{ "success": false, "message": "Instance not found on your account." }
| Code | Meaning |
|---|---|
| 401 | Missing, malformed, or invalid API key. |
| 403 | Account suspended or subscription expired. |
| 404 | The instance doesn't exist or isn't yours. |
| 409 | The instance exists but isn't connected right now. |
| 422 | Missing or invalid fields in your request. |
| 429 | Would exceed your plan's monthly message limit. |
| 502 | The WhatsApp connection failed to send — usually transient, safe to retry shortly. |
Rate limits & quota
Each plan includes a monthly message allowance. send-bulk.php checks remaining quota up front and rejects the whole batch with 429 if it would push you over, so you can show the client a clear "limit reached" message instead of a partial send. Check your current usage and limit from your dashboard's billing page.
Phone number format
Numbers are normalized automatically — both local (07XXXXXXXX) and international (2547XXXXXXXX) formats are accepted for Kenyan numbers. Any entries that can't be normalized are silently dropped from a bulk request, and the response's queued count reflects only the valid ones — compare it against the length of the list you sent if you need to know which were skipped.