Channel API
Channel API berbeda dengan API key workspace (Pengaturan → API, lihat API). API key untuk membaca dan
mengelola data Onix; kunci channel (onx_ch_…) hanya bisa mengirim pesan masuk ke satu channel API itu.
Membuat channel API
- Buka Kelola → Channel, klik Tambah channel, lalu pilih Channel API (paket Pro/Custom; butuh akses mengelola channel).
- Isi nama channel (mis. nama aplikasi Anda — tampil di Interaction & filter) dan URL webhook (boleh diisi nanti), lalu klik Buat channel API.
- Salin kunci channel (
onx_ch_…) dan secret webhook (whsec_…). Kunci channel hanya tampil sekali — simpan di server Anda; bila hilang, ganti kunci. Secret bisa dilihat lagi di pengaturan channel. - Opsional: unggah ikon (PNG/JPG/WebP persegi, maks 512 KB) supaya percakapan dari sistem ini mudah dikenali di Interaction.
Satu channel API memakai satu slot channel; kuotanya digabung dengan nomor WhatsApp, alamat email, dan livechat (Pro 4 channel). Bila paket turun ke Free, channel API dijeda dan pesan masuk ditolak (402) sampai paket aktif lagi.
Mengirim pesan pelanggan ke Onix
Kirim setiap pesan pelanggan dari sistem Anda ke endpoint ini dengan kunci channel di header Authorization:
curl -s -X POST "https://onix.sassly.ai/api/v1/channel-api/messages" \
-H "Authorization: Bearer $ONIX_CHANNEL_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "order-1029",
"contact": {"id": "u_981", "name": "Budi Santoso", "email": "[email protected]", "phone": "6281234567890"},
"message": {"id": "m_5521", "text": "Halo, pesanan saya belum sampai",
"attachments": [{"url": "https://cdn.tokoanda.com/foto.jpg", "name": "foto.jpg"}]}
}'
| Kolom | Keterangan |
|---|---|
conversation_id | Opsional, maks 100 karakter. ID percakapan di sistem Anda (mis. nomor pesanan). Bawaan = contact.id (satu percakapan per pelanggan). Pesan dengan conversation_id yang sama masuk ke percakapan yang sama selama masih terbuka. |
contact.id | Wajib, maks 100 karakter. ID pelanggan di sistem Anda. |
contact.name, contact.email, contact.phone | Opsional. Pelanggan dicocokkan lewat contact.id, lalu email atau nomor HP — pelanggan yang sudah pernah chat lewat WhatsApp, email, atau livechat masuk ke kontak yang sama. |
message.id | Wajib, unik per channel, maks 100 karakter. Mengirim ulang pesan dengan message.id yang sama aman: dijawab 200 dengan "duplicate": true dan tidak dicatat dua kali. |
message.text | Maks 4.000 karakter. Wajib bila tanpa lampiran. |
message.attachments | Opsional, maks 5: [{"url", "name"}]. URL harus https ke host publik; Onix mengunduh dan menyimpannya privat (maks 10 MB per file, pengalihan/redirect tidak diikuti). Lampiran ke-2 dan seterusnya menjadi pesan sendiri dengan id {message.id}#2, #3, … |
message.sent_at | Opsional, ISO 8601 (mis. 2026-10-11T03:00:00Z). Bawaan = waktu diterima; waktu di masa depan dipotong ke sekarang. |
Hasil 201 Created (atau 200 untuk duplikat):
{"data": {"message_id": 678, "interaction_id": 45, "interaction_number": "INT-000045", "duplicate": false}}
Punya file di server Anda sendiri? Kirim sebagai multipart/form-data dengan files[]; kolom lain memakai tanda kurung:
curl -s -X POST "https://onix.sassly.ai/api/v1/channel-api/messages" \
-H "Authorization: Bearer $ONIX_CHANNEL_KEY" \
-F "contact[id]=u_981" -F "message[id]=m_5522" -F "message[text]=Ini struknya" \
-F "files[][email protected]"
- Percakapan mengikuti aturan yang sama dengan channel lain: pesan ke percakapan yang sudah Solved/Closed membuka percakapan baru (nomor INT baru).
- Salam awal & pesan di luar jam kerja (bila dinyalakan di pengaturan channel) dikirim ke sistem Anda lewat webhook dengan
sender.type="auto". - Pesan masuk muncul di Interaction secara real-time, dengan ikon dan nama channel API Anda.
Menerima balasan agen (webhook)
Setiap balasan agen dan balasan otomatis dikirim Onix ke URL webhook sebagai POST JSON (event message.created, selalu
dikirim). Event conversation.updated (status Solved/Closed/dibuka lagi atau penanggung jawab berubah) bisa dinyalakan di
pengaturan channel. URL webhook harus https ke host publik (bukan alamat jaringan internal).
POST https://api.tokoanda.com/onix/webhook
Content-Type: application/json
User-Agent: Onix-Webhook/1.0 (+https://onix.sassly.ai/docs/api-channel)
X-Onix-Event: message.created
X-Onix-Delivery: 0c6f7a52-2b1e-4b8e-9d0a-5d7f3c1e9a41
X-Onix-Timestamp: 1791630130
X-Onix-Signature: sha256=8f2c…
{
"event": "message.created",
"channel": {"id": 9, "name": "Aplikasi Mitra"},
"conversation": {"id": "order-1029", "interaction_id": 45, "number": "INT-000045", "status": "open"},
"contact": {"id": "u_981", "name": "Budi Santoso"},
"message": {
"id": 680,
"type": "document",
"text": "Halo kak, ini resinya ya",
"attachments": [{"name": "resi.pdf", "mime": "application/pdf", "size": 48211, "url": "https://onix.sassly.ai/api/v1/channel-api/files/…"}],
"sender": {"type": "agent", "name": "Sari"},
"sent_at": "2026-10-11T03:02:10Z"
}
}
{
"event": "conversation.updated",
"change": "status",
"channel": {"id": 9, "name": "Aplikasi Mitra"},
"conversation": {"id": "order-1029", "interaction_id": 45, "number": "INT-000045", "status": "solved", "assignee": {"name": "Sari"}},
"contact": {"id": "u_981", "name": "Budi Santoso"},
"updated_at": "2026-10-11T03:20:00Z"
}
conversation.iddancontact.idadalah ID dari sistem Anda, jadi Anda bisa meneruskan balasan tanpa menyimpan ID Onix.message.idadalah ID pesan Onix (untuk status terkirim/dibaca).sender.type:agent(balasan agen) atauauto(balasan otomatis). Satu pesan Onix membawa paling banyak satu lampiran;urllampiran bertanda tangan dan berlaku 7 hari tanpa login.- Endpoint Anda harus menjawab 2xx dalam 10 detik. Bila tidak, pengiriman dicoba ulang dengan jeda 1 menit, 5 menit, 15 menit, 1 jam, 6 jam — jumlah coba ulang diatur per channel (0–5, bawaan 5). Setelah itu pesan ditandai Gagal di Interaction beserta alasannya, dan agen bisa Kirim ulang.
- Pesan dikirim berurutan per percakapan: pesan berikutnya menunggu sampai yang sebelumnya terkirim atau gagal.
X-Onix-Deliverysama di setiap coba ulang — simpan dan abaikan yang sudah pernah diproses.- URL webhook belum diisi? Balasan agen tetap tersimpan di Onix tetapi berstatus Gagal "URL webhook belum diatur".
Memeriksa tanda tangan webhook
X-Onix-Signature = sha256= + HMAC-SHA256 (heksadesimal) dari X-Onix-Timestamp + "." + body mentah dengan secret
webhook (whsec_…) sebagai kunci. Hitung ulang dari body sebelum di-parse sebagai JSON, bandingkan dengan fungsi
waktu-konstan, dan tolak timestamp yang lebih dari 5 menit dari jam server Anda (mencegah pengiriman ulang oleh pihak lain).
PHP
<?php
$secret = getenv('ONIX_WEBHOOK_SECRET'); // whsec_…
$body = file_get_contents('php://input'); // body mentah
$timestamp = $_SERVER['HTTP_X_ONIX_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_ONIX_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (!hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
if ($event['event'] === 'message.created') {
// Teruskan $event['message']['text'] ke pelanggan $event['contact']['id']
// di percakapan $event['conversation']['id'].
}
http_response_code(200);
Node.js (Express)
import crypto from 'node:crypto';
import express from 'express';
const app = express();
// Body mentah: tanda tangan dihitung dari byte yang dikirim Onix.
app.post('/onix/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-Onix-Timestamp') || '';
const signature = req.get('X-Onix-Signature') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.ONIX_WEBHOOK_SECRET)
.update(timestamp + '.').update(req.body).digest('hex');
const valid = signature.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
if (!valid) return res.sendStatus(401);
const event = JSON.parse(req.body);
// … teruskan event.message ke pelanggan event.contact.id
res.sendStatus(200);
});
Python (Flask)
import hashlib, hmac, json, os, time
from flask import Flask, abort, request
app = Flask(__name__)
@app.post("/onix/webhook")
def onix_webhook():
body = request.get_data() # byte mentah
timestamp = request.headers.get("X-Onix-Timestamp", "")
signature = request.headers.get("X-Onix-Signature", "")
expected = "sha256=" + hmac.new(os.environ["ONIX_WEBHOOK_SECRET"].encode(),
timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature) or abs(time.time() - int(timestamp or 0)) > 300:
abort(401)
event = json.loads(body)
# … teruskan event["message"] ke pelanggan event["contact"]["id"]
return "", 200
Status terkirim & dibaca (opsional)
Supaya agen melihat balasannya sudah sampai, kirim POST https://onix.sassly.ai/api/v1/channel-api/messages/{id}/status dengan kunci channel dan
{"status": "delivered"} atau {"status": "read"}, memakai message.id dari webhook. Status hanya naik
(Terkirim → Diterima → Dibaca) dan tampil langsung di Interaction.
Pengaturan & alat uji
| Tab | Isi |
|---|---|
| Webhook | Nama channel, ikon, URL webhook, event yang dikirim, jumlah coba ulang, serta Tes webhook (mengirim event ping sekarang dan menampilkan kode HTTP & lamanya) dan Kirim pesan uji (mensimulasikan pesan masuk dari sistem Anda; balas pesan itu di Interaction untuk mencoba webhook). |
| Kredensial | Endpoint pesan masuk, kunci channel (awalan & kapan terakhir dipakai) dengan tombol Ganti kunci (kunci lama langsung ditolak), serta secret webhook: Lihat secret & Ganti secret. |
| Jam kerja & otomatis | Ikuti jam kerja workspace atau jam kerja sendiri, salam awal, dan pesan di luar jam kerja — sama dengan semua channel (lihat Livechat bagian jam kerja). |
| Riwayat | 50 pengiriman webhook terakhir: waktu, event, status (Terkirim, Dicoba ulang, Gagal), kode HTTP, lama, dan keterangan. |
Di Interaction
- Percakapan channel API masuk tab Chat dengan ikon yang Anda unggah (atau ikon API bawaan) dan nama channel di item & filter Channel.
- Agen membalas dengan teks, satu lampiran, template, artikel KB, atau catatan internal (catatan tidak pernah dikirim ke sistem Anda). Reaksi, edit, tarik pesan, dan kutip tidak tersedia.
- Status balasan: Memproses (menunggu webhook) → Terkirim (endpoint menjawab 2xx) → Diterima/Dibaca bila sistem Anda mengirim status. Gagal menampilkan alasannya (mis. "Endpoint menjawab HTTP 500") dengan tombol Kirim ulang.
- Penugasan mengikuti aturan biasa (tanpa antrian Ambil chat — itu khusus livechat). Target respons channel API punya nilai sendiri (bawaan 15 menit kerja) — lihat KPI & SLA.
Kode galat
Galat memakai format yang sama dengan API Onix: {"error": {"code", "message", "fields"}}.
| HTTP | Artinya |
|---|---|
401 | Kunci channel tidak ada, salah, atau sudah diganti. |
402 | Paket workspace bukan Pro/Custom — channel API dijeda. |
404 | Status: pesan tidak ditemukan di channel ini (bukan balasan agen channel itu). |
409 | Channel API sudah dihapus atau sedang tidak aktif. |
422 | Isian tidak valid (per kolom di fields, mis. message.id), lampiran tidak bisa diunduh, atau lebih besar dari 10 MB. |
429 | Lebih dari 120 request per menit per kunci channel. Tunggu sesuai header Retry-After. |
Keamanan
- Kunci channel hanya disimpan sebagai sidik (hash) dan bisa diganti kapan saja; secret webhook disimpan terenkripsi. Simpan keduanya di server Anda, jangan di aplikasi mobile atau JavaScript browser.
- Onix hanya menghubungi URL https ke host publik (URL webhook & URL lampiran) dan tidak mengikuti pengalihan, supaya isian tidak bisa dipakai menjangkau jaringan internal.
- Selalu periksa tanda tangan dan timestamp webhook sebelum memprosesnya.
- Menghapus channel API langsung menghentikan kuncinya dan membatalkan webhook yang masih menunggu coba ulang; riwayat percakapan diarsipkan.
Spesifikasi lengkap (termasuk bagian webhooks OpenAPI 3.1): /docs/openapi.yaml.