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.

WhatsApp, Messenger, and Instagram are trademarks of Meta Platforms, Inc.
SyBox™ is an independent product built on Meta Cloud API.

SMART SOUQ

SMART SOUQ SARL AU · RC Marrakech N° 154779 · RC Fès N° 87323 · ICE 003587569000031
© 2026. All rights reserved.