Developer Documentation
Send WhatsApp messages with an API you already know
If you've called the WhatsApp Cloud API, you already know ours. Same path, same JSON body, same Bearer auth — point your code at a new base URL and you're done.
01Quickstart
Three things and your first message is on its way: the base URL, a device key, and the messages endpoint.
Base URL
https://api.smartsybox.com
Authentication
Authorization: Bearer <YOUR_DEVICE_KEY>
Content type
application/json
The Endpoint
POST
/v26.0/{phone-number-id}/messages
The version segment is accepted in any v form (v26.0, v1.0, …) — keep whatever your current code uses. The {phone-number-id} is your WhatsApp number's ID, exactly as with Meta.
02Send your first message
A plain text message. The body is the standard Cloud API payload — we pass it through to Meta untouched.
cURL
curl -X POST https://api.smartsybox.com/v26.0/PHONE_NUMBER_ID/messages \
-H "Authorization: Bearer YOUR_DEVICE_KEY" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"to": "15551234567",
"type": "text",
"text": { "body": "Hello from SyBox 👋" }
}'
C# · HttpClient
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "YOUR_DEVICE_KEY");
string json = @"{
""messaging_product"": ""whatsapp"",
""to"": ""15551234567"",
""type"": ""text"",
""text"": { ""body"": ""Hello from SyBox"" }
}";
var res = await http.PostAsync(
"https://api.smartsybox.com/v26.0/PHONE_NUMBER_ID/messages",
new StringContent(json, Encoding.UTF8, "application/json"));
Console.WriteLine(await res.Content.ReadAsStringAsync());
The Response
You get back exactly what Meta returns, with the same HTTP status — so any existing Cloud API client library parses it unchanged.
200 OK · application/json
{
"messaging_product": "whatsapp",
"contacts": [{ "input": "15551234567", "wa_id": "15551234567" }],
"messages": [{ "id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgARGBI…" }]
}
03Any message type works
Because the body is forwarded untouched, every Cloud API message type is supported — templates, images, documents, interactive messages. Here's a template send.
Request body · template
{
"messaging_product": "whatsapp",
"to": "15551234567",
"type": "template",
"template": {
"name": "hello_world",
"language": { "code": "en_US" }
}
}
04Show your data beside the chat
When an agent opens a conversation, SyBox calls YOUR endpoint and shows what you return right beside the chat — the customer's orders, balance, tickets. We send the customer's phone, or their email on an email conversation.
Request · SyBox → your endpoint
POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: lookup
# body: { "data": "<json string>" } — the decoded "data":
{
"phone": "15551234567",
"email": "customer@example.com",
"ref": ""
}
Your reply · application/json
{
"renderAs": "table",
"content": [
{ "Order": "#10432", "Status": "Shipped", "Total": "1,250 MAD" }
]
}
renderAs
Set renderAs to tell SyBox how to display your content — one of:
table
Rows & columns. content = an array of flat objects (or { rows: [ … ] }). Object keys become the column headers.
cards · kpi
Compact tiles (a balance, an order count). content = an array of { label, value } (or { cards: [ … ] }).
feed · list · thread
A timeline of rich cards. content = an array of { title, text, date, tags, media:[{ type, url, name }] }.
message
A single message-style card (one record laid out as a note).
html
Your own trusted HTML — content = a string. Use only for markup you generate yourself.
sections
Several blocks at once: content = { sections: [ { title, renderAs, content } ] } — mix a table + cards + a feed in one reply.
json
The default when renderAs is omitted — SyBox pretty-prints your content as-is.
Add a sybox_ref to any table row or card and it becomes clickable — SyBox calls you again with that ref so you can return the single record's detail.
We send both phone and email — either may be empty. Match on whichever identifies the customer in your system, and reply with { renderAs, content }.
05File a case from your own system
This is the route an ERP or accounting system uses. Your program does not send a formatted message about a complaint — it asks SyBox to open the case. One record, one place, one number your staff can quote back to the customer.
cURL
curl -X POST "https://api.smartsybox.com/v1/case" \
-H "Authorization: Bearer $SYBOX_CASE_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_unique_id": "CUST-10432",
"header": "Screen replacement not delivered",
"description": "Paid on 12 Aug, promised in 3 days, still nothing.",
"ext_ref": "TICKET-99817"
}'
The fields
customer_unique_id
Your own record id for the customer — the same key customer sync uses. Falls back to phone when you have no id.
header / description
At least one is required. The header is the line staff see in the list.
ext_ref
Your ticket number. Send it. A retry with the same ext_ref returns the case that already exists instead of filing a twin — making the call safe to repeat after a timeout.
The customer must already exist. A case filed against a customer nobody can find is refused rather than inventing one. Create the customer with POST /v1/sync first.
Use a key of kind 'case'. A relay key (the one that sends messages) is refused here with 403, on purpose: a key that can message your customers should not also be able to open records in your CRM.
06Push a message in from another program
For anything that is not WhatsApp: a note from your point of sale, an alert from a device, a line from a legacy system. It lands in the right conversation, keyed by phone number, marked with the name of the program that sent it.
cURL
curl -X POST "https://api.smartsybox.com/v1/inbound" \
-H "Authorization: Bearer $SYBOX_INBOUND_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "212600112233",
"text": "Order 4821 has left the warehouse."
}'
Inbound only, by design. This route writes into the conversation; it does not send anything to the customer. Use the messages route above for that.
07Errors
Errors are returned verbatim from Meta, with Meta's own status code and error shape — nothing is rewritten.
4xx · application/json
{
"error": {
"message": "(#131030) Recipient phone number not in allowed list",
"type": "OAuthException",
"code": 131030
}
}
08Getting a device key
Keys are created inside your workspace and carry the routing themselves — no subdomain, no account id in the request.
- Open your workspace → Settings → API keys and create a device key.
- Each key is bound to one number and can be revoked at any time.
- Your real WhatsApp token never leaves our server — the key stands in for it.
- The gateway is off by default; enabling API access for the workspace switches it on.
Trademarks & attribution
SyBox is an independent product and is not affiliated with, endorsed by, or sponsored by Meta Platforms, Inc. 'WhatsApp', 'WhatsApp Business' and the WhatsApp Cloud API are trademarks of Meta Platforms, Inc.
Our gateway deliberately mirrors the shape of the WhatsApp Cloud API — the same request path, JSON body and Bearer authentication — purely so that developers already familiar with it can adopt ours with little to no change. It is a compatibility layer, not a copy of Meta's service.
All rights in the original WhatsApp Cloud API, its design and its documentation remain with Meta Platforms, Inc. Any request you send is forwarded to Meta's official API under your own account and is subject to Meta's terms and policies.