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.
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…" }]
}
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.00" }
]
}
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 }.
Product search (X-Sybox-Action: products)
The same endpoint can also answer product searches. The agent types what the customer is asking for, SyBox sends it as "q", and your reply is drawn as product cards next to the chat — with a one-tap Send that puts the product link in the composer.
Request · SyBox → your endpoint
POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: products
# body: { "data": "<json string>" } — the decoded "data":
{
"q": "wireless keyboard",
"phone": "15551234567",
"email": "customer@example.com",
"ref": ""
}
Your reply · application/json
{
"content": [
{
"name": "Wireless Keyboard K380",
"price": 449,
"oldPrice": 520,
"currency": "USD",
"available": true,
"stock": 12,
"image": "https://cdn.example.com/k380.jpg",
"link": "https://shop.example.com/p/k380",
"note": "Ships in 24h"
}
]
}
name
The only required field. A product with nothing but a name still renders as a tidy card.
price · oldPrice · currency
Numbers, not formatted strings. Send oldPrice only when there is a genuine previous price — the discount badge is calculated from the pair.
available · stock
available is true/false; stock is an optional count shown beside it. Omit them entirely if you do not track stock — an absent field draws nothing, and is never read as out of stock.
image
A direct https image URL. Anything that fails to load falls back to a neutral placeholder.
link
The product page URL. Without it the card is read-only — Send to chat appears only when there is something to send.
note
One short free line under the price — delivery time, a variant, a condition.
Only the endpoint you already built: same URL, same key, same { "data": "…" } envelope. Look at X-Sybox-Action to tell a product search from a customer lookup. Reply with content as a plain array (or { items: [ … ] }).
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.