Developer guide
Connect your app, website or system to Botzo with three tools: sending WhatsApp messages, Mochi (the AI assistant that answers your customers), and webhooks that tell your server about everything the moment it happens.
This guide is written for every developer, even if it is your first time working with WhatsApp. Read this page first, then jump to the section you need.
What can you build?
| You want to… | Use | Section |
|---|---|---|
| Send order updates, verification codes or invoices on WhatsApp | Messaging API | Sending WhatsApp messages |
| Put an "Ask Mochi" chat in your mobile app or website with your own design | Mochi API | Mochi API |
| Have your server know right away when a customer replies, a message is read, or someone asks for a person | Webhooks | Webhooks |
| Add contacts from your CRM or store and launch a campaign | Contacts and campaigns API | Contacts, templates and campaigns |
Everything that happens through the API also shows in the Botzo inbox, where your team can answer directly.
Base URL
All requests go to:
https://botzo.net/api
- Requests and responses are JSON in UTF-8 (Arabic and emoji are fine).
- Always send
Accept: application/jsonandContent-Type: application/json. - HTTPS only.
Start in 5 minutes
1) Create an API key
In the dashboard: Developer tools → Access tokens. Name the key (for example "Store server"), pick its permissions, and press Generate API key. Copy it right away: it is shown only once.
Important: a key is like a password. Keep it in your server's environment (
BOTZO_API_KEY), never in front-end code or a mobile app. Details in Keys and security.
2) Check the key works
curl https://botzo.net/api/verify \
-H "Authorization: Bearer $BOTZO_API_KEY" \
-H "Accept: application/json"
const res = await fetch('https://botzo.net/api/verify', {
headers: { Authorization: `Bearer ${process.env.BOTZO_API_KEY}`, Accept: 'application/json' },
});
console.log(res.status, await res.json());
$response = Http::withToken(env('BOTZO_API_KEY'))->acceptJson()->get('https://botzo.net/api/verify');
echo $response->status(); // 200
import os, requests
r = requests.get("https://botzo.net/api/verify",
headers={"Authorization": f"Bearer {os.environ['BOTZO_API_KEY']}", "Accept": "application/json"})
print(r.status_code, r.json())
Response:
{
"statusCode": 200,
"message": "API key is valid and active"
}
3) Send your first message
To send free text, the customer must have messaged you in the last 24 hours (a WhatsApp rule, see WhatsApp rules). To try it, send "hi" from your phone to your organization's WhatsApp number, then:
curl -X POST https://botzo.net/api/send \
-H "Authorization: Bearer $BOTZO_API_KEY" \
-H "Accept: application/json" -H "Content-Type: application/json" \
-d '{"phone": "+966501234567", "message": "Your order is on its way 🚚"}'
const res = await fetch('https://botzo.net/api/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BOTZO_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ phone: '+966501234567', message: 'Your order is on its way 🚚' }),
});
const result = await res.json();
console.log(result.message_id); // keep it to follow the message status
$result = Http::withToken(env('BOTZO_API_KEY'))->acceptJson()
->post('https://botzo.net/api/send', ['phone' => '+966501234567', 'message' => 'Your order is on its way 🚚'])
->json();
echo $result['message_id'];
r = requests.post("https://botzo.net/api/send",
headers={"Authorization": f"Bearer {os.environ['BOTZO_API_KEY']}", "Accept": "application/json"},
json={"phone": "+966501234567", "message": "Your order is on its way 🚚"})
print(r.json()["message_id"])
Success returns 200 with a message_id. If WhatsApp refuses the message you get a clear error code such as outside_24h_window; see Errors.
4) Receive your customers' replies
In Developer tools → Webhooks press Use the test receiver, then Add webhook. Send a message from your phone and press Refresh in the test receiver: you will see the message.received event exactly as your server will get it, with its signature check. When your server is ready, put its URL instead. Details in Webhooks.
Response format
Success: always includes statusCode (same as the HTTP status), plus fields for the request.
Error: the same shape across the whole API:
{
"statusCode": 422,
"code": "outside_24h_window",
"message": "(#131047) Re-engagement message",
"request_id": "9fb64a88-f0f1-4a36-a1e8-0ba3eef81360"
}
| Field | Meaning |
|---|---|
statusCode |
The HTTP status |
code |
Build your logic on this: a stable value. Full list in Errors |
message |
Human-readable text. It may change, so don't branch on it |
request_id |
The request's id. Send it to support so we find the request at once. Also in the X-Request-Id header |
errors |
(validation errors only) the invalid fields and why |
Conventions
- Phone numbers in international E.164 format with the country code:
+966501234567. Without+, we add it. - Times are UTC. Most fields are ISO 8601 such as
2026-10-22T18:23:06+00:00; a few use2026-10-22 18:23:06(also UTC). - Ids: WhatsApp messages have a
message_idstarting withwamid.; contacts, groups and templates have auuid; Mochi conversations have aconversation_id. - The
Server-Timingheader comes with every response and shows where the time went, for exampleapp;dur=27.4, db;dur=12.1, meta;dur=980:appis the whole request,metais WhatsApp's servers,dbis the database. Very handy when something feels slow.
Next steps
- Pick the right key and learn the security rules: Keys and security
- Using WhatsApp? Read WhatsApp rules first; it prevents most errors.
- Want ready code? Go to Complete examples.