API WhatsApp
Hantar mesej pertama anda#
Mesej teks biasa. Badan mesej adalah muatan standard Cloud API — kami memajukannya terus ke Meta tanpa sebarang perubahan.
POST/v26.0/{phone-number-id}/messagesAuthorization: Bearer <DEVICE_KEY>
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" }
}'const res = await fetch('https://api.smartsybox.com/v26.0/PHONE_NUMBER_ID/messages', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.SYBOX_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
messaging_product: 'whatsapp',
to: '15551234567',
type: 'text',
text: { body: 'Hello from SyBox' }
})
});
console.log(res.status, await res.json());import os, requests
r = requests.post(
"https://api.smartsybox.com/v26.0/PHONE_NUMBER_ID/messages",
headers={"Authorization": "Bearer " + os.environ["SYBOX_KEY"]},
json={
"messaging_product": "whatsapp",
"to": "15551234567",
"type": "text",
"text": {"body": "Hello from SyBox"},
},
timeout=30,
)
print(r.status_code, r.json())$ch = curl_init('https://api.smartsybox.com/v26.0/PHONE_NUMBER_ID/messages');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SYBOX_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'messaging_product' => 'whatsapp',
'to' => '15551234567',
'type' => 'text',
'text' => ['body' => 'Hello from SyBox'],
]),
]);
echo curl_exec($ch);using System.Net.Http.Headers;
using System.Text;
using var http = new HttpClient(); // in a real app, keep one HttpClient for the whole app
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("SYBOX_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());
Respons API#
Anda menerima jawapan tepat seperti yang dikembalikan oleh Meta, lengkap dengan status HTTP yang sama — membolehkan pustaka klien Cloud API sedia ada anda memprosesnya tanpa perubahan.
200 OK · application/json {
"messaging_product": "whatsapp",
"contacts": [{ "input": "15551234567", "wa_id": "15551234567" }],
"messages": [{ "id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgARGBI…" }]
}
Sistem anda dalam SyBox
Pamerkan data sistem anda terus di sebelah sembang#
Setiap kali ejen membuka perbualan, SyBox memanggil titik akhir sistem ANDA dan memaparkan maklumat yang dikembalikan tepat di sebelah sembang — pesanan pelanggan, baki akaun, atau tiket sokongan. Kami menghantar nombor telefon pelanggan, atau e-mel mereka untuk perbualan e-mel.
Tambah titik akhir anda dalam Tetapan › Integrasi › API ERP. Setiap panggilan ialah POST dengan kunci anda dalam Authorization dan permintaan dalam satu medan, data, yang mengandungi rentetan JSON — jadi mana-mana pihak boleh menambah medan kemudian tanpa merosakkan pihak yang lain. Jawab dalam masa 15 saat.
POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: lookup
X-Sybox-Lang: en
X-Sybox-Theme: light
X-Sybox-Agent: 6f1c…
X-Sybox-Number: 104857600000000
Content-Type: application/json
{ "data": "{\"phone\":\"15551234567\",\"email\":\"customer@example.com\",\"ref\":\"\"}" }{
"renderAs": "table",
"content": [
{ "Order": "#10432", "Status": "Shipped", "Total": "$1,250.00", "sybox_ref": "10432" },
{ "Order": "#10388", "Status": "Delivered", "Total": "$310.00", "sybox_ref": "10388" }
]
}
Setiap panggilan juga memberitahu siapa yang bertanya: X-Sybox-Lang (bahasa pengguna — jawab dalam bahasa itu), X-Sybox-Theme (light atau dark, untuk balasan html), X-Sybox-Agent (id pengguna) dan X-Sybox-Number (talian tempat perbualan itu berada).
Kami menghantar nombor telefon dan e-mel — salah satu mungkin kosong. Padankan dengan maklumat yang mengenal pasti pelanggan dalam sistem anda, dan balas dengan { renderAs, content }.
renderAs#
Tetapkan renderAs untuk menentukan cara SyBox memaparkan kandungan anda — pilih salah satu:
| renderAs | Penerangan |
|---|
table | Baris dan lajur. content ialah tatasusunan objek rata (atau { rows: [ … ] }); kuncinya menjadi pengepala lajur. |
cards · kpi | Jubin kecil, seperti baki atau bilangan pesanan. content ialah tatasusunan { label, value } (atau { cards: [ … ] }). |
feed · list · thread | Garis masa kad. content ialah tatasusunan { title, text, date, tags, media: [{ type, url, name }] }. |
message | Satu rekod yang dipaparkan sebagai satu kad gaya mesej. |
html | HTML anda sendiri, sebagai rentetan dalam content. Hanya untuk markup yang anda jana sendiri. |
sections | Beberapa blok dalam satu balasan: content ialah { sections: [ { title, renderAs, content } ] }. |
json | Lalai apabila renderAs ditinggalkan: SyBox memaparkan content anda sebagai JSON berformat. |
Tambah sybox_ref pada mana-mana baris jadual atau kad untuk menjadikannya boleh diklik — SyBox akan memanggil sistem anda semula dengan rujukan tersebut untuk memaparkan butiran rekod berkenaan.
Carian produk (X-Sybox-Action: products)#
Titik akhir yang sama juga boleh menjawab carian produk. Pengguna menaip perkara yang diminta pelanggan, SyBox menghantarnya sebagai "q", dan balasan anda dipaparkan sebagai kad produk di sebelah sembang — dengan fungsi Hantar satu ketikan yang memasukkan pautan produk ke dalam penggubah mesej.
POST YOUR_ERP_URL
Authorization: Bearer YOUR_ERP_KEY
X-Sybox-Action: products
# the decoded "data":
{ "q": "wireless keyboard", "phone": "15551234567", "email": "customer@example.com", "ref": "" }{
"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"
}
]
}
| Medan | Penerangan |
|---|
namewajib | Satu-satunya medan wajib. Produk yang hanya mempunyai nama tetap akan dipaparkan sebagai kad yang kemas. |
price · oldPrice · currency | Gunakan nilai angka, bukan rentetan berformat. Hantar oldPrice hanya jika terdapat harga asal sebenar — lencana diskaun akan dikira secara automatik daripada perbandingan kedua-duanya. |
available · stock | available bernilai true/false; manakala stock ialah jumlah pilihan yang dipaparkan di sebelahnya. Abaikan kedua-duanya jika anda tidak menguruskan inventori — medan yang tiada tidak akan memaparkan apa-apa dan tidak sekali-kali dianggap sebagai kehabisan stok. |
image | Pautan imej https langsung. Sebarang imej yang gagal dimuatkan akan digantikan secara automatik dengan latar belakang neutral. |
link | Pautan ke halaman produk. Tanpanya kad hanya untuk paparan — butang Hantar ke sembang hanya muncul apabila terdapat sesuatu untuk dihantar. |
note | Satu baris teks ringkas di bawah harga — tempoh penghantaran, pilihan varian, atau syarat promosi. |
Hanya gunakan titik akhir yang telah anda bina: URL yang sama, kunci yang sama, dan format { "data": "…" } yang sama. Rujuk pengepala X-Sybox-Action untuk membezakan antara carian produk dan semakan pelanggan. Balas dengan content dalam bentuk tatasusunan mudah (atau { items: [ … ] }).
Peristiwa
Webhook: peristiwa pada pelayan anda#
Tambah titik akhir anda dalam Tetapan › Integrasi › Webhook, pilih peristiwa dan nombor, dan SyBox akan menghantar (POST) setiap peristiwa kepadanya sebaik sahaja ia berlaku. Peristiwa WhatsApp tiba dalam format webhook Meta sendiri, jadi pengendali yang ditulis untuk Meta berfungsi tanpa perubahan.
| Peristiwa | Penerangan |
|---|
messageMesej masuk | Mesej daripada pelanggan. |
statusStatus mesej | Dihantar, sampai, dibaca atau gagal — untuk mesej yang anda hantar. |
reactionReaksi | Pelanggan memberi reaksi pada mesej. |
Permintaan · SyBox → anda POST YOUR_WEBHOOK_URL
Content-Type: application/json
X-Hub-Signature-256: sha256=5d1f0c…
x-sybox-signature: sha256=5d1f0c…
x-sybox-event: message
x-sybox-timestamp: 1761400000
{
"object": "whatsapp_business_account",
"entry": [{
"id": "WABA_ID",
"changes": [{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": { "display_phone_number": "15550001111", "phone_number_id": "PHONE_NUMBER_ID" },
"contacts": [{ "profile": { "name": "Sara" }, "wa_id": "15551234567" }],
"messages": [{
"from": "15551234567",
"id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgASGBQ…",
"timestamp": "1761400000",
"type": "text",
"text": { "body": "Is my order shipped?" }
}]
}
}]
}]
}
Media. Pautan Meta sendiri memerlukan token Meta untuk dibuka, jadi SyBox menggantikannya dengan pautan bertandatangan ke salinan failnya sendiri, sah selama 24 jam. Nota suara juga boleh membawa kata-katanya dalam sybox.transcription, apabila webhook memintanya.
Saluran lain — Messenger, Instagram, Telegram dan Sembang Langsung — tiba dalam format SyBox sendiri, untuk peristiwa mesej sahaja:
{
"object": "sybox",
"event": "message",
"channel": "telegram",
"line": "8123456789",
"workspace": "yourworkspace",
"contact": { "key": "tg:6423115118", "name": "Sara" },
"message": {
"id": "812345",
"timestamp": 1761400000,
"type": "image",
"text": "",
"caption": "The broken part",
"media": { "url": "https://api.smartsybox.com/…", "mime": "image/jpeg" }
}
}
Kunci tandatangan#
| Pengepala | Penerangan |
|---|
X-Hub-Signature-256 | sha256= diikuti HMAC-SHA256 heks bagi badan mentah, dikunci dengan rahsia tandatangan webhook — pengepala dan kaedah yang sama seperti Meta. |
x-sybox-signature | Nilai yang sama, supaya titik akhir yang turut menerima panggilan Meta sendiri dapat membezakan panggilan kami. |
x-sybox-event | message, status atau reaction. |
x-sybox-timestamp | Masa ia dihantar, dalam saat Unix. |
x-sybox-signature-rsa | Tandatangan kedua: rsa-sha256= dan RSA-SHA256 (PKCS#1 v1.5) dalam base64 bagi x-sybox-timestamp, satu titik, dan badan mentah. |
x-sybox-key-id | Kunci kami yang mana telah menghasilkannya. Kunci awam berada di https://api.smartsybox.com/.well-known/sybox-webhook-key. |
Semak tandatangan pada bait mentah, sebelum anda menghuraikannya, dan bandingkan dalam masa malar:
const crypto = require('crypto');
// express.raw: the signature is over the bytes as sent, so read them before any JSON parser.
app.post('/sybox/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sent = Buffer.from(req.get('X-Hub-Signature-256') || '');
const want = Buffer.from('sha256=' + crypto
.createHmac('sha256', process.env.SYBOX_WEBHOOK_SECRET)
.update(req.body)
.digest('hex'));
if (sent.length !== want.length || !crypto.timingSafeEqual(sent, want)) return res.sendStatus(401);
res.sendStatus(200); // answer first, then do the work
const event = JSON.parse(req.body);
const kind = req.get('x-sybox-event'); // message | status | reaction
});$raw = file_get_contents('php://input');
$want = 'sha256=' . hash_hmac('sha256', $raw, getenv('SYBOX_WEBHOOK_SECRET'));
$sent = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';
if (!hash_equals($want, $sent)) {
http_response_code(401);
exit;
}
http_response_code(200);
$event = json_decode($raw, true);
$kind = $_SERVER['HTTP_X_SYBOX_EVENT'] ?? ''; // message | status | reactionimport hashlib, hmac, os
from flask import Flask, abort, request
app = Flask(__name__)
@app.post("/sybox/webhook")
def sybox_webhook():
raw = request.get_data()
want = "sha256=" + hmac.new(os.environ["SYBOX_WEBHOOK_SECRET"].encode(), raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(want, request.headers.get("X-Hub-Signature-256", "")):
abort(401)
event = request.get_json()
kind = request.headers.get("x-sybox-event") # message | status | reaction
return "", 200using System.Security.Cryptography;
using System.Text;
app.MapPost("/sybox/webhook", async (HttpRequest req) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
byte[] raw = ms.ToArray();
string secret = Environment.GetEnvironmentVariable("SYBOX_WEBHOOK_SECRET")!;
byte[] mac = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), raw);
byte[] want = Encoding.ASCII.GetBytes("sha256=" + Convert.ToHexString(mac).ToLowerInvariant());
byte[] sent = Encoding.ASCII.GetBytes(req.Headers["X-Hub-Signature-256"].ToString());
if (!CryptographicOperations.FixedTimeEquals(want, sent)) return Results.Unauthorized();
string kind = req.Headers["x-sybox-event"]; // message | status | reaction
return Results.Ok();
});
Tidak mahu menyimpan rahsia kongsi pada pelayan anda? Semak x-sybox-signature-rsa dengan kunci awam kami sebagai gantinya. Walau apa pun caranya, tolak cap masa yang berusia lebih daripada lima minit.
Jawab dengan sebarang 2xx dalam masa 15 saat. Selain itu — ralat, tamat masa, ubah hala — akan dicuba semula selepas 1, 2, 4, 8, 16 dan 32 minit, kemudian digugurkan. Satu peristiwa boleh tiba lebih daripada sekali: gunakan id mesej untuk mengabaikan ulangan. Alamat mestilah awam dan https.
Untuk menguji, hantar mesej ke nombor anda dan lihat Penghantaran terakhir pada kad webhook: ia menunjukkan jawapan pelayan anda.
Sembang Langsung
Sembang Langsung#
Letakkan sembang di tapak web anda: pelawat menulis di sana, pasukan anda menjawab dalam SyBox. Tambah tapak web dalam Tetapan › Pemesejan › Saluran, pada kad Sembang Langsung; tetingkap yang terbuka, Kod untuk tapak anda, memberi anda kod dan kunci di bawah. Tiga kunci rahsia itu dipaparkan sekali sahaja.
| Kunci | Bermula dengan | Kegunaannya |
|---|
| Kunci awam | lcpk_ | Diletakkan dalam halaman anda. Selamat untuk diterbitkan: ia hanya menamakan tapak web, dan sembang hanya dipaparkan pada Alamat tapak web anda. |
| Kunci tandatangan untuk pengguna log masuk | lcid_ | Pelayan anda sahaja. Menandatangani setiap pengguna log masuk, supaya tiada sesiapa boleh menulis sebagai orang lain. |
| Kunci pelayan (untuk skrin sembang anda sendiri) | lcsk_ | Pelayan anda sahaja. Hanya untuk tapak yang membina skrin sembangnya sendiri dan bukan menggunakan sembang siap. |
| Kunci tandatangan balasan | lcwh_ | Pelayan anda sahaja. Membuktikan bahawa balasan yang dihantar ke pelayan anda datang daripada SyBox. |
Sembang siap hanya memerlukan kod. Kunci tandatangan adalah untuk tapak yang mempunyai akaun; kunci pelayan dan kunci tandatangan balasan hanya untuk tapak yang mempunyai skrin sembangnya sendiri.
Mematikan laman web menyembunyikan sembang serta-merta. Panggilan pelayan anda masih diterima dan disimpan.
Tambah sembang ke tapak anda#
Tampal kod sekali ke dalam setiap halaman, tepat sebelum tag penutup body. Sembang hanya dipaparkan pada alamat dalam Alamat tapak web, dan warna, kedudukan, tajuk serta ucapan alu-aluannya ditetapkan dalam SyBox, bukan dalam kod.
<script async src="https://api.smartsybox.com/lc/w.js" data-key="lcpk_YOUR_PUBLIC_KEY"></script>
WordPress: muat turun pemalam kami daripada tetingkap yang sama. Shopify: dalam aplikasi Shopify SyBox, hidupkan Sembang Langsung di kedai ini, kemudian SyBox Live Chat di bawah App embeds — pelanggan yang log masuk dikenali tanpa perlu berbuat apa-apa lagi.
Pengguna log masuk: kunci tandatangan#
Apabila pengguna log masuk ke tapak anda, pelayan anda memberitahu sembang siapa mereka dengan token pendek — JWT, HS256 — yang ditandatangani dengan kunci tandatangan. Pengguna itu kemudian mempunyai satu perbualan atas nama mereka, pada setiap peranti, dan tiada sesiapa boleh membukanya dengan menaip id orang lain.
- Selepas log masuk, pelayan anda membina token daripada tuntutan (claims) di bawah.
- Halaman menyerahkannya kepada sembang sebagai
identity, sebelum kod sembang. - Selepas log masuk tanpa memuat semula halaman, panggil
SyBoxChat('identify', token) sebagai gantinya.
| Medan | Penerangan |
|---|
subwajibstring | Id pengguna anda, sehingga 120 aksara. Ia tidak boleh bermula dengan v_. |
expwajibnumber | Tamat tempoh, dalam saat Unix — tidak lebih daripada satu hari ke hadapan. Sepuluh minit sudah memadai: token hanya dibaca apabila sembang dibuka. |
namestring | Nama yang dipaparkan oleh perbualan. |
emailstring | Alamat e-mel pengguna. |
phonestring | Nombor telefon pengguna. |
picturestring | Alamat https foto pengguna, sehingga 500 aksara. SyBox menyimpan salinannya sendiri, dan mengambilnya semula pada log masuk seterusnya apabila alamat berubah. |
function b64url(string $s): string { return rtrim(strtr(base64_encode($s), '+/', '-_'), '='); }
$header = b64url(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
$payload = b64url(json_encode([
'sub' => (string) $user->id,
'name' => $user->name,
'email' => $user->email,
'exp' => time() + 600, // ten minutes
]));
$signature = b64url(hash_hmac('sha256', "$header.$payload", getenv('SYBOX_LC_SIGNING_KEY'), true));
$token = "$header.$payload.$signature";const crypto = require('crypto');
const b64url = (s) => Buffer.from(s).toString('base64url');
const header = b64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
const payload = b64url(JSON.stringify({
sub: String(user.id),
name: user.name,
email: user.email,
exp: Math.floor(Date.now() / 1000) + 600 // ten minutes
}));
const signature = crypto.createHmac('sha256', process.env.SYBOX_LC_SIGNING_KEY)
.update(header + '.' + payload).digest('base64url');
const token = header + '.' + payload + '.' + signature;import base64, hashlib, hmac, json, os, time
def b64url(b: bytes) -> str:
return base64.urlsafe_b64encode(b).rstrip(b"=").decode()
header = b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
payload = b64url(json.dumps({
"sub": str(user.id),
"name": user.name,
"email": user.email,
"exp": int(time.time()) + 600, # ten minutes
}).encode())
key = os.environ["SYBOX_LC_SIGNING_KEY"].encode()
signature = b64url(hmac.new(key, f"{header}.{payload}".encode(), hashlib.sha256).digest())
token = f"{header}.{payload}.{signature}"using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
static string B64Url(byte[] b) => Convert.ToBase64String(b).TrimEnd('=').Replace('+', '-').Replace('/', '_');
string header = B64Url(JsonSerializer.SerializeToUtf8Bytes(new { alg = "HS256", typ = "JWT" }));
string payload = B64Url(JsonSerializer.SerializeToUtf8Bytes(new {
sub = user.Id.ToString(),
name = user.Name,
email = user.Email,
exp = DateTimeOffset.UtcNow.AddMinutes(10).ToUnixTimeSeconds()
}));
byte[] key = Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("SYBOX_LC_SIGNING_KEY"));
string signature = B64Url(HMACSHA256.HashData(key, Encoding.ASCII.GetBytes(header + "." + payload)));
string token = header + "." + payload + "." + signature;
<script>
window.SyBoxChatConfig = { identity: "TOKEN_FROM_YOUR_SERVER", locale: "en" };
</script>
<script async src="https://api.smartsybox.com/lc/w.js" data-key="lcpk_YOUR_PUBLIC_KEY"></script>
Buat token pada pelayan anda sahaja. Kunci tandatangan dalam halaman web membolehkan sesiapa sahaja menulis sebagai mana-mana pengguna anda. Dan jangan sekali-kali meletakkan id pengguna biasa dalam halaman sebagai ganti token: ini akan membolehkan sesiapa sahaja memilih perbualan siapa yang hendak dibaca.
Apabila Hanya pengguna log masuk tapak saya dihidupkan, pelawat tanpa token tidak akan melihat sembang.
Pelawat yang bersembang sebelum log masuk akan ditanya sekali, dalam pelayar yang sama, sama ada mahu meneruskan perbualan itu dengan akaun mereka. Anda tidak perlu berbuat apa-apa untuk ini.
Kawal sembang daripada halaman anda#
Kod sembang menambah satu fungsi pada halaman anda, SyBoxChat:
SyBoxChat('open'); // open the chat
SyBoxChat('close'); // close it
SyBoxChat('identify', token); // after a sign-in without a page reload
SyBoxChat('locale', 'fr'); // the chat's language
SyBoxChat('on', 'message', function (m) {
// a reply arrived
});
SyBoxChat('on', 'open', function () { /* the chat opened */ });
SyBoxChat('on', 'close', function () { /* the chat closed */ });
// Before the chat's code, every setting is optional:
window.SyBoxChatConfig = {
identity: 'TOKEN_FROM_YOUR_SERVER', // a signed-in user (see above)
name: 'Sara', email: 'sara@example.com', // a visitor without an account: fills the form for them
locale: 'ar',
serviceWorker: 'auto' // 'auto' | '/your-sw.js' | 'site' | 'off'
};
Pemberitahuan selepas tapak anda ditutup#
Semasa halaman tapak anda terbuka, balasan dipaparkan sebagai pemberitahuan dengan sendirinya. Untuk sampai kepada pelawat selepas tapak anda ditutup, pelayar memerlukan service worker pada domain anda sendiri: sajikan satu baris ini sebagai /sybox-lc-sw.js di akar tapak anda, sebagai application/javascript.
try { importScripts('https://api.smartsybox.com/lc/sw.js'); } catch (e) {}
Pilih mod dalam SyBox (Pemberitahuan apabila laman web ditutup) atau dalam halaman dengan serviceWorker: "auto" (fail di atas, lalai), laluan anda sendiri, "site" (letakkan baris yang sama di bahagian atas service worker anda sendiri) atau "off".
Sembang tidak sekali-kali menggantikan service worker yang sudah ada pada tapak anda, dan fail itu tiada pengendali fetch, jadi ia tidak pernah melihat sebarang permintaan tapak anda. Pemalam WordPress menyajikan fail itu untuk anda. Safari iPhone tidak memaparkan pemberitahuan untuk tapak web biasa.
Skrin sembang anda sendiri: kunci pelayan#
Tapak atau aplikasi yang mempunyai skrin sembangnya sendiri berhubung dengan SyBox daripada pelayannya dan bukan menggunakan sembang siap. Setiap panggilan membawa Authorization: Bearer lcsk_…. Pelayan anda menamakan pengguna dengan id anda sendiri, dan dipercayai untuk berbuat demikian kerana ia memegang kunci.
| Panggilan | Penerangan |
|---|
POST /v1/livechat/messages | Pengguna anda menulis. client_id menjadikan cubaan semula selamat: id yang sama disimpan sekali sahaja ("duplicate": 1). |
POST /v1/livechat/upload | Fail, sebagai data borang multipart: file, user_id, client_id. Sehingga 16 MB: imej, suara, video, PDF, teks dan dokumen Office. |
GET /v1/livechat/messages?user_id=&since=&before=&limit= | Perbualan: mesej selepas since, dan agents_read_id, iaitu mesej terbaru pengguna anda yang telah dibaca oleh ejen. |
POST /v1/livechat/read | Pengguna anda telah membaca balasan sehingga up_to. |
POST /v1/livechat/edit | Pengguna anda menyunting mesejnya sendiri, dalam masa 15 minit. |
POST /v1/livechat/delete | Pengguna anda memadam mesejnya sendiri untuk semua orang, dalam masa 24 jam. |
POST /v1/livechat/react | Reaksi pada mana-mana mesej; emoji kosong akan membuangnya. |
POST /v1/livechat/typing | Pengguna anda sedang menaip: hantar on: 1 setiap beberapa saat dan on: 0 apabila mereka berhenti. |
curl -X POST https://api.smartsybox.com/v1/livechat/messages \
-H "Authorization: Bearer $SYBOX_LC_SERVER_KEY" \
-H "Content-Type: application/json" \
-d '{
"user": { "id": "u42", "name": "Sara Ali", "email": "sara@example.com", "locale": "ar" },
"message": { "client_id": "a1b2c3", "text": "Hi, is my order on its way?", "reply_to": "" }
}'{ "ok": 1, "id": 981, "guid": "7c9e…", "duplicate": 0 }{ "user_id": "u42", "up_to": 990 } // read
{ "user_id": "u42", "id": 981, "text": "…" } // edit
{ "user_id": "u42", "id": 981 } // delete
{ "user_id": "u42", "id": 990, "emoji": "👍" } // react
{ "user_id": "u42", "on": 1 } // typing
Mesej, dalam sejarah dan dalam balasan:
{
"id": 990,
"guid": "b81d…",
"dir": "out", // "in" = your user wrote it, "out" = your team
"type": "image", // text | image | audio | video | file
"text": "Here is the tracking page",
"media": { "url": "https://api.smartsybox.com/…", "mime": "image/png", "name": "tracking.png", "w": 1080, "h": 720 },
// a voice note or a video also has "secs"
"status": 3, // on your user's messages: 1 received, 3 read by an agent
"reply_to": "7c9e…",
"client": "a1b2c3", // on your user's messages: the client_id you sent
"react_us": "", // your team's reaction on it
"react_me": "👍", // your user's reaction on it
"at": "2026-10-25T09:41:07Z",
"edited": 0
}
Sejarah pengguna yang belum pernah menulis menjawab 404 unknown_user: paparkan perbualan kosong.
Pautan media bertandatangan dan berfungsi selama satu jam; minta semula untuk mendapatkan yang baharu. SyBox tidak sekali-kali mengambil fail daripada alamat yang anda hantar: muat naiknya. Sehingga 120 panggilan seminit bagi setiap tapak web.
Balasan pada pelayan anda: kunci tandatangan balasan#
Masukkan Alamat pelayan anda untuk balasan pada tapak web. Apabila pasukan anda membalas, menyunting, memadam atau membaca, SyBox menghantar (POST) peristiwa itu ke sana, ditandatangani dengan kunci tandatangan balasan.
| Pengepala | Penerangan |
|---|
x-sybox-signature | t=TIMESTAMP,v1=SIGNATURE — TIMESTAMP dalam saat Unix, SIGNATURE ialah HMAC-SHA256 dalam hex bagi TIMESTAMP.BODY (body mentah), dikunci dengan kunci tandatangan balasan. |
x-sybox-event | message.created, message.updated, message.deleted atau messages.read. |
x-sybox-delivery | Sama pada setiap cubaan semula bagi satu peristiwa: gunakannya untuk mengabaikan ulangan. |
Badan mengandungi event, line_id, user_id dan message — atau message_id untuk pemadaman, dan read_id untuk messages.read: mesej pengguna anda telah dibaca sehingga id itu.
const crypto = require('crypto');
app.post('/sybox/livechat', express.raw({ type: 'application/json' }), (req, res) => {
const parts = Object.fromEntries((req.get('x-sybox-signature') || '').split(',').map(p => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(401); // older than five minutes
const want = Buffer.from(crypto.createHmac('sha256', process.env.SYBOX_LC_REPLY_KEY)
.update(t + '.').update(req.body).digest('hex'));
const sent = Buffer.from(parts.v1 || '');
if (sent.length !== want.length || !crypto.timingSafeEqual(sent, want)) return res.sendStatus(401);
res.sendStatus(200);
const delivery = req.get('x-sybox-delivery'); // seen it already? ignore
const evt = JSON.parse(req.body); // { event, line_id, user_id, message | message_id | read_id }
});$raw = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_SYBOX_SIGNATURE'] ?? ''), $sig);
$t = (int) ($sig['t'] ?? 0);
$want = hash_hmac('sha256', $t . '.' . $raw, getenv('SYBOX_LC_REPLY_KEY'));
if (abs(time() - $t) > 300 || !hash_equals($want, $sig['v1'] ?? '')) {
http_response_code(401);
exit;
}
http_response_code(200);
$delivery = $_SERVER['HTTP_X_SYBOX_DELIVERY'] ?? ''; // seen it already? ignore
$evt = json_decode($raw, true);import hashlib, hmac, os, time
from flask import abort, request
@app.post("/sybox/livechat")
def sybox_livechat():
raw = request.get_data()
sig = dict(p.split("=", 1) for p in request.headers.get("x-sybox-signature", "").split(",") if "=" in p)
t = int(sig["t"]) if sig.get("t", "").isdigit() else 0 # a malformed header is a 401, not a crash
want = hmac.new(os.environ["SYBOX_LC_REPLY_KEY"].encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
if abs(time.time() - t) > 300 or not hmac.compare_digest(want, sig.get("v1", "")):
abort(401)
delivery = request.headers.get("x-sybox-delivery") # seen it already? ignore
evt = request.get_json()
return "", 200using System.Security.Cryptography;
using System.Text;
app.MapPost("/sybox/livechat", async (HttpRequest req) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
byte[] raw = ms.ToArray();
var sig = new Dictionary<string, string>();
foreach (var part in req.Headers["x-sybox-signature"].ToString().Split(','))
{
var kv = part.Split('=', 2);
if (kv.Length == 2) sig[kv[0].Trim()] = kv[1].Trim(); // a malformed header is a 401, not a crash
}
if (!long.TryParse(sig.GetValueOrDefault("t"), out long t) ||
Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return Results.Unauthorized();
byte[] signedBytes = Encoding.ASCII.GetBytes(t + ".").Concat(raw).ToArray();
string replyKey = Environment.GetEnvironmentVariable("SYBOX_LC_REPLY_KEY")!;
byte[] mac = HMACSHA256.HashData(Encoding.UTF8.GetBytes(replyKey), signedBytes);
byte[] want = Encoding.ASCII.GetBytes(Convert.ToHexString(mac).ToLowerInvariant());
byte[] sent = Encoding.ASCII.GetBytes(sig.GetValueOrDefault("v1", ""));
if (!CryptographicOperations.FixedTimeEquals(want, sent)) return Results.Unauthorized();
return Results.Ok();
});
Semak tandatangan pada badan mentah, tolak t yang berusia lebih daripada lima minit, dan jawab 2xx dengan cepat. Selain itu akan dicuba semula selepas 10 s, 30 s, 2 min, 10 min dan 30 min, kemudian digugurkan. SyBox hanya memanggil alamat awam dan tidak sekali-kali mengikut ubah hala.
Kod sebab#
Setiap jawapan Sembang Langsung ialah JSON — {"ok": 1, …}, atau {"ok": 0, "error": "CODE"} dengan kod dan bukan ayat:
| Kod | Status | Penerangan |
|---|
unauthorized | 401 | Kunci pelayan salah atau telah diganti. |
invalid_json invalid_payload invalid_user_id | 400 | Permintaan tidak mengikut bentuk yang dijangka. |
empty_message no_file empty_file | 400 | Tiada teks dan tiada fail. |
too_long | 400 | Teks yang diedit melebihi 4,096 aksara. |
not_an_emoji | 400 | emoji bukan emoji. |
not_found | 404 | Tiada mesej sedemikian, atau mesej itu bukan milik pengguna ini. |
too_late | 409 | Masa untuk mengedit atau memadam telah tamat. |
file_type_not_allowed | 400 | Jenis fail ini tidak diterima. |
file_too_large | 413 | Fail melebihi 16 MB. |
blocked | 403 | Pasukan anda telah menyekat pengguna ini. |
unknown_user | 404 | Belum ada perbualan untuk id pengguna ini. |
rate_limited | 429 | Terlalu banyak panggilan: perlahankan dan cuba lagi. |
maintenance | 503 | SyBox sedang dikemas kini: cuba lagi selepas Retry-After saat. |
server_error | 500 | Sesuatu telah gagal di pihak kami. |
Menggantikan kunci#
Kehilangan kunci, atau rasa ia telah bocor? Pada kad tapak web, klik Kunci tandatangan baharu, Kunci pelayan baharu atau Kunci tandatangan balasan baharu. Kunci pelayan baharu membiarkan kunci lama berfungsi selama satu hari, supaya anda boleh bertukar tanpa sebarang gangguan; kunci-kunci lain berhenti serta-merta.