Agent Bot
Bot yang ikut membalas dan mengatur percakapan secara otomatis sebelum diserahkan ke agen.
Agent Bot adalah "agen robot" yang ikut bertugas di sebuah inbox. Berbeda dengan Webhook yang hanya memberi tahu, Agent Bot punya identitas dan token sendiri, sehingga bisa bertindak balik di dalam percakapan: membalas pelanggan, mengubah status, menugaskan agen, sampai menyerahkan percakapan ke manusia.
Kapan dipakai
- Balasan otomatis di luar jam kerja ("Toko tutup, kami balas besok pagi").
- Chatbot FAQ yang menjawab pertanyaan umum sebelum agen turun tangan.
- Triage — menyaring percakapan lalu menugaskannya ke tim yang tepat.
- Menu interaktif sederhana untuk mengarahkan pelanggan.
Cara kerja
Pelanggan kirim pesan
│
▼
pembalasan.id ──POST──▶ Bot Anda (outgoing_url)
▲ │
│ ▼
└──── API ◀──── Bot memutuskan: balas / ubah status / serahkan ke agen- Pelanggan mengirim pesan ke inbox yang punya Agent Bot aktif.
- pembalasan.id mengirim event ke
outgoing_urlbot (mirip webhook). - Bot memproses, lalu bertindak balik lewat API memakai tokennya sendiri — misalnya mengirim balasan.
- Bila butuh manusia, bot melakukan handoff: mengubah status percakapan menjadi Terbuka agar diambil agen. Selama bot menangani, percakapan biasanya ditahan di status Tunda (pending) sehingga tidak mengganggu antrean agen.
Event yang diterima bot
Agent Bot menerima event seputar inbox tempat ia bertugas: message_created,
message_updated, conversation_created, conversation_opened,
conversation_resolved, conversation_status_changed, conversation_updated, dan
webwidget_triggered.
Cara membuat
1. Buat bot — daftarkan nama dan outgoing_url (alamat yang akan menerima event):
curl -X POST 'https://api-c6tw.pembalasan.id/api/v1/accounts/{account_id}/agent_bots' \
-H 'api_access_token: TOKEN_ANDA' \
-H 'Content-Type: application/json' \
-d '{
"name": "Bot Sapaan",
"description": "Membalas otomatis & triage",
"outgoing_url": "https://sistem-anda.com/bot"
}'Respons memuat access token bot — token inilah yang dipakai bot untuk membalas lewat API. Lihat referensi API: Create an Account Agent Bot.
2. Sambungkan bot ke inbox — pasang bot ke inbox yang diinginkan:
curl -X POST 'https://api-c6tw.pembalasan.id/api/v1/accounts/{account_id}/inboxes/{inbox_id}/set_agent_bot' \
-H 'api_access_token: TOKEN_ANDA' \
-H 'Content-Type: application/json' \
-d '{ "agent_bot": 1 }'Untuk melepas bot dari inbox, kirim { "agent_bot": null }. Lihat
referensi API: Add or remove agent bot.
Selain dipasang ke seluruh inbox, bot juga bisa ditugaskan per percakapan tertentu — berguna jika hanya sebagian percakapan yang perlu ditangani bot.
Bentuk data yang diterima
Setiap kiriman ke outgoing_url berisi field event (nama event) di level atas
plus datanya. Contoh ringkas (sebagian field) untuk message_created saat pelanggan
mengirim pesan:
{
"event": "message_created",
"id": 12345,
"content": "Halo, apakah pesanan saya sudah dikirim?",
"message_type": "incoming",
"content_type": "text",
"private": false,
"created_at": "2026-06-28T10:00:00.000Z",
"account": { "id": 1, "name": "Toko Saya" },
"inbox": { "id": 7, "name": "WhatsApp Toko" },
"sender": {
"id": 88,
"name": "Budi Santoso",
"phone_number": "+628123456789",
"email": null
},
"conversation": {
"id": 42,
"status": "open",
"channel": "Channel::Whatsapp",
"meta": {
"sender": { "id": 88, "name": "Budi Santoso", "type": "contact" },
"assignee": null
}
}
}message_typebisaincoming(dari pelanggan),outgoing(dari agen/bot),activity, atautemplate. Bot umumnya hanya meresponsincoming.senderberbeda menurut pengirim: kontak (seperti di atas), agen (type: "user"), atau bot lain (type: "agent_bot").- Untuk event percakapan (mis.
conversation_status_changed), payload berisi data percakapan +event, pluschanged_attributessaat statusnya berubah.
Verifikasi tanda tangan (HMAC)
Agar yakin request benar-benar dari pembalasan.id (bukan pihak lain), verifikasi tanda tangan pada setiap kiriman. Setiap POST membawa header berikut:
| Header | Isi |
|---|---|
X-Chatwoot-Signature | sha256=<hmac> — tanda tangannya |
X-Chatwoot-Timestamp | Waktu kirim (unix), ikut ditandatangani |
X-Chatwoot-Delivery | ID unik pengiriman (untuk mencegah proses ganda) |
Tanda tangan dihitung dengan HMAC-SHA256, memakai secret bot sebagai kunci atas
gabungan timestamp + titik + body mentah:
sha256=HMAC_SHA256( secret, timestamp + "." + body_mentah )secret bot ada di response API saat membuat bot (field secret).
Gunakan body mentah persis seperti diterima. Jangan parse JSON lalu susun ulang — perubahan spasi atau urutan kunci akan membuat tanda tangan tidak cocok.
Contoh di Next.js (Route Handler):
import crypto from 'crypto';
export async function POST(req) {
const rawBody = await req.text(); // mentah, sebelum JSON.parse
const signature = req.headers.get('x-chatwoot-signature');
const timestamp = req.headers.get('x-chatwoot-timestamp');
const expected =
'sha256=' +
crypto
.createHmac('sha256', process.env.BOT_SECRET)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
const a = Buffer.from(signature ?? '');
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return new Response('invalid signature', { status: 401 });
}
const payload = JSON.parse(rawBody);
// ...proses event, lalu balas lewat API memakai token bot...
return Response.json({ ok: true });
}Bandingkan tanda tangan dengan fungsi constant-time (timingSafeEqual,
hash_equals), bukan ===, untuk mencegah timing attack. Simpan
X-Chatwoot-Delivery untuk mengabaikan event yang terkirim ulang (idempotensi).
Membalas & menyerahkan ke agen (handoff)
Bot bertindak balik lewat API memakai access token-nya. Dua aksi terpenting:
Membalas pelanggan — kirim pesan keluar:
curl -X POST 'https://api-c6tw.pembalasan.id/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages' \
-H 'api_access_token: TOKEN_BOT' \
-H 'Content-Type: application/json' \
-d '{ "content": "Halo! Ada yang bisa kami bantu?", "message_type": "outgoing" }'Menyerahkan ke agen manusia (handoff) — ubah status percakapan ke open
agar diambil agen:
curl -X POST 'https://api-c6tw.pembalasan.id/api/v1/accounts/{account_id}/conversations/{conversation_id}/toggle_status' \
-H 'api_access_token: TOKEN_BOT' \
-H 'Content-Type: application/json' \
-d '{ "status": "open" }'Dipanggil dengan token bot pada percakapan yang sedang ditangani bot, ini
memicu handoff resmi — percakapan berpindah dari bot ke antrean agen. Untuk
menutup percakapan yang sudah tuntas, kirim "status": "resolved".
{conversation_id} diambil dari conversation.id pada payload event.
Akhiri setiap percakapan dengan jelas. Setelah bot mencoba membantu,
serahkan ke agen (status: open) bila butuh manusia, atau tandai
resolved bila tuntas. Jika tidak, percakapan bisa tertahan di antrean bot
dan tidak muncul di daftar agen.
Contoh handler lengkap (PHP)
Handler minimal yang sudah benar: verifikasi HMAC, balas 200 cepat, proses hanya
pesan masuk, balas, lalu handoff bila bot tak punya jawaban. Daftarkan URL file
ini sebagai outgoing_url bot Anda.
<?php
// webhook.php — handler Agent Bot pembalasan.id
const BASE_URL = 'https://api-c6tw.pembalasan.id';
const ACCOUNT_ID = 1; // account id Anda
const BOT_TOKEN = 'ACCESS_TOKEN_BOT'; // untuk membalas & handoff
const BOT_SECRET = 'SECRET_BOT'; // untuk verifikasi HMAC
// 1) Hanya terima POST
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') { http_response_code(405); exit; }
// 2) Body MENTAH (wajib utuh untuk HMAC — jangan decode lalu encode ulang)
$rawBody = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_CHATWOOT_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_CHATWOOT_TIMESTAMP'] ?? '';
// 3) Verifikasi tanda tangan (constant-time)
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, BOT_SECRET);
if (!hash_equals($expected, $signature)) { http_response_code(401); exit('invalid signature'); }
// 4) Balas 200 cepat, lalu proses (kalau server mendukung fastcgi)
http_response_code(200);
header('Content-Type: text/plain');
echo 'ok';
if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); }
// 5) Hanya proses pesan MASUK dari pelanggan
$body = json_decode($rawBody, true) ?: [];
if (($body['event'] ?? '') !== 'message_created' || ($body['message_type'] ?? '') !== 'incoming') {
exit;
}
$convId = (int)($body['conversation']['id'] ?? 0);
$text = trim((string)($body['content'] ?? ''));
if ($convId === 0) { exit; }
// 6) Logika bot Anda — contoh balasan sederhana
if (stripos($text, 'jam buka') !== false) {
cw_reply($convId, 'Toko kami buka 08.00-21.00 WIB setiap hari.');
exit;
}
// 7) Bot tak punya jawaban -> serahkan ke agen manusia
cw_handoff($convId);
// --- Helper API pembalasan.id ---------------------------------------
function cw_reply(int $convId, string $content): void {
cw_post("/conversations/$convId/messages", ['content' => $content, 'message_type' => 'outgoing']);
}
function cw_handoff(int $convId): void {
cw_post("/conversations/$convId/toggle_status", ['status' => 'open']);
}
function cw_post(string $path, array $payload): void {
$ch = curl_init(BASE_URL . '/api/v1/accounts/' . ACCOUNT_ID . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'api_access_token: ' . BOT_TOKEN],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
curl_exec($ch);
curl_close($ch);
}BOT_TOKEN adalah access token bot (dari response saat membuat bot), bukan
token admin — agar balasan ter-atribusi ke bot dan handoff berjalan resmi.
Jika Anda hanya perlu diberi tahu saat ada kejadian (tanpa membalas otomatis), Webhook lebih sederhana dan tidak perlu mengelola token bot.