Dokumentasi WhatsApp API
https://api.kirimkan.my.id/api/v1
Autentikasi
Authorization: Bearer wa_live_xxxxxxxxxxxxxxxxxxxxxxxx
Setiap kunci dibatasi scope. Permintaan di luar scope akan gagal dengan kode insufficient_scope. Cabut kunci dari menu API Keys bila bocor.
Header berikut dikembalikan oleh setiap respons API.
| Header | Keterangan |
|---|---|
| X-Request-Id | ID permintaan. Sertakan saat menghubungi dukungan. Sama dengan request_id pada respons error. |
| X-RateLimit-Limit | Batas permintaan per menit untuk API key Anda sesuai paket aktif. |
| X-RateLimit-Remaining | Sisa permintaan pada jendela satu menit berjalan. |
| Retry-After | Hanya pada status 429: jumlah detik sebelum boleh mencoba lagi. |
Kirim Pesan Teks
https://api.kirimkan.my.id/api/v1/messages
Mengirim pesan teks instan ke nomor WhatsApp tujuan.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| Content-Type | Ya | application/json | Format body request. |
| Idempotency-Key | Tidak | order-1001 | Kunci unik per pesan (maks. 120 karakter). Permintaan ulang dengan kunci yang sama mengembalikan pesan yang sama. Alias: X-Idempotency-Key. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"Content-Type": "application/json",
"Idempotency-Key": "order-1001",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| number | string | Ya | Nomor tujuan. |
| message | string | Ya | Isi pesan. |
| device_id | string | Tidak | ID perangkat pengirim. |
| rotator_id | string | Tidak | ID rotator pengiriman. |
| scheduled_at | string | Tidak | Jadwal kirim (ISO 8601). |
{
"number": "6281234567890",
"message": "Halo, pesanan Anda sedang diproses.",
"device_id": "dev_uuid_abc123",
"scheduled_at": "2026-10-23T09:00:00+07:00"
}
Dikirim sebagai JSON body. Field opsional boleh dihilangkan.
Gunakan Idempotency-Key unik per pesan agar tidak terkirim ganda.
curl -X POST https://api.kirimkan.my.id/api/v1/messages \
-H "Authorization: Bearer wa_live_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1001" \
-d '{
"number": "6281234567890",
"message": "Halo, pesanan Anda sedang diproses."
}'
<?php
$response = Http::withToken('wa_live_xxx')
->withHeaders(['Idempotency-Key' => 'order-1001'])
->post('https://api.kirimkan.my.id/api/v1/messages', [
'number' => '6281234567890',
'message' => 'Halo, pesanan Anda sedang diproses.',
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer wa_live_xxx',
'Content-Type': 'application/json',
'Idempotency-Key': 'order-1001'
},
body: JSON.stringify({
number: '6281234567890',
message: 'Halo, pesanan Anda sedang diproses.'
})
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "msg_uuid_abc123",
"status": "queued",
"to": "6281234567890",
"scheduled_at": null
},
"idempotent": false
}
{
"data": {
"id": "msg_uuid_abc123",
"status": "queued",
"to": "6281234567890",
"scheduled_at": null
},
"idempotent": true
}
{
"error": {
"code": "validation_error",
"message": "number wajib diisi.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope messages:send diperlukan.",
"request_id": "req_01HZX..."
}
}
Kirim File
https://api.kirimkan.my.id/api/v1/messages
Mengirim berkas atau media dengan caption ke nomor tujuan.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| Content-Type | Ya | application/json | Format body request. |
| Idempotency-Key | Tidak | order-1001 | Kunci unik per pesan (maks. 120 karakter). Permintaan ulang dengan kunci yang sama mengembalikan pesan yang sama. Alias: X-Idempotency-Key. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"Content-Type": "application/json",
"Idempotency-Key": "order-1001",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| number | string | Ya | Nomor tujuan. |
| media_url | string | Tidak | URL HTTPS publik. |
| media_base64 | string | Tidak | Berkas dalam base64. |
| media_type | string | Tidak | MIME berkas. |
| caption | string | Tidak | Teks pendamping. |
| filename | string | Tidak | Nama berkas. |
| device_id | string | Tidak | ID perangkat pengirim. |
| scheduled_at | string | Tidak | Jadwal kirim (ISO 8601). |
{
"number": "6281234567890",
"media_url": "https://example.com/invoice.pdf",
"media_type": "application/pdf",
"caption": "Invoice pesanan Anda.",
"filename": "invoice.pdf"
}
Dikirim sebagai JSON body. Field opsional boleh dihilangkan.
Isi salah satu media_url atau media_base64.
curl -X POST https://api.kirimkan.my.id/api/v1/messages \
-H "Authorization: Bearer wa_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"number": "6281234567890",
"media_url": "https://example.com/invoice.pdf",
"media_type": "application/pdf",
"caption": "Invoice pesanan Anda.",
"filename": "invoice.pdf"
}'
<?php
$response = Http::withToken('wa_live_xxx')
->post('https://api.kirimkan.my.id/api/v1/messages', [
'number' => '6281234567890',
'media_url' => 'https://example.com/invoice.pdf',
'media_type' => 'application/pdf',
'caption' => 'Invoice pesanan Anda.',
'filename' => 'invoice.pdf',
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/messages', {
method: 'POST',
headers: {
'Authorization': 'Bearer wa_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
number: '6281234567890',
media_url: 'https://example.com/invoice.pdf',
media_type: 'application/pdf',
caption: 'Invoice pesanan Anda.',
filename: 'invoice.pdf'
})
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "msg_uuid_abc123",
"status": "queued",
"to": "6281234567890",
"scheduled_at": null
},
"idempotent": false
}
{
"error": {
"code": "validation_error",
"message": "Pesan atau media wajib diisi.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "feature_locked",
"message": "Paket Gratis belum mendukung media. Upgrade ke Pro.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope messages:send diperlukan.",
"request_id": "req_01HZX..."
}
}
Status Pesan
https://api.kirimkan.my.id/api/v1/messages/{id}
Mengambil detail pesan berdasarkan ID.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| id | string | Ya | ID pesan. |
{
"id": "msg_uuid_abc123"
}
Dikirim sebagai bagian path, misalnya /messages/msg_uuid_abc123. Tanpa body.
Untuk daftar pesan gunakan GET /messages?status=&limit=&offset=.
curl https://api.kirimkan.my.id/api/v1/messages/msg_uuid_abc123 \ -H "Authorization: Bearer wa_live_xxx"
<?php
$response = Http::withToken('wa_live_xxx')
->get('https://api.kirimkan.my.id/api/v1/messages/msg_uuid_abc123');
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/messages/msg_uuid_abc123', {
headers: {
'Authorization': 'Bearer wa_live_xxx'
}
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "msg_uuid_abc123",
"to": "6281234567890",
"status": "sent",
"source": "api",
"body": "Halo, pesanan Anda sedang diproses.",
"rendered_body": "Halo, pesanan Anda sedang diproses.",
"media": null,
"provider_message_id": "wamid.xxx",
"error": null,
"created_at": "2026-10-21T10:00:00.000Z",
"sent_at": "2026-10-21T10:00:02.000Z",
"attempts": [
{
"attempt": 1,
"status": "sent",
"error": null,
"at": "2026-10-21T10:00:01.000Z"
}
],
"events": [
{
"status": "sent",
"source": "worker",
"at": "2026-10-21T10:00:02.000Z"
}
]
}
}
{
"error": {
"code": "not_found",
"message": "Pesan tidak ditemukan.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope messages:read diperlukan.",
"request_id": "req_01HZX..."
}
}
| Status | Arti |
|---|---|
| queued | Masuk antrean pengiriman. |
| scheduled | Dijadwalkan untuk waktu tertentu. |
| processing | Sedang diproses oleh worker. |
| retry_pending | Menunggu percobaan ulang otomatis. |
| sent | Diterima server WhatsApp. |
| failed | Gagal permanen; cek error. |
| canceled | Dibatalkan sebelum terkirim. |
| expired | Kedaluwarsa sebelum sempat dikirim. |
| unknown | Status tidak dapat dipastikan. |
| received | Pesan masuk dari pelanggan. |
Kirim ulang pesan gagal dengan POST /messages/{id}/retry dan batalkan pesan antrean dengan POST /messages/{id}/cancel.
Daftar Kontak
https://api.kirimkan.my.id/api/v1/contacts
Menampilkan daftar kontak workspace.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| q | string | Tidak | Cari nama atau nomor. |
| group_id | string | Tidak | Filter grup. |
| tag_id | string | Tidak | Filter tag. |
| limit | integer | Tidak | Maksimal 200. |
| offset | integer | Tidak | Lewati baris. |
{
"q": "budi",
"limit": 50,
"offset": 0
}
Dikirim sebagai query string, misalnya ?q=budi&limit=50&offset=0. Tanpa body.
curl "https://api.kirimkan.my.id/api/v1/contacts?limit=50&offset=0" \ -H "Authorization: Bearer wa_live_xxx"
<?php
$response = Http::withToken('wa_live_xxx')
->get('https://api.kirimkan.my.id/api/v1/contacts', [
'limit' => 50,
'offset' => 0,
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/contacts?limit=50&offset=0', {
headers: {
'Authorization': 'Bearer wa_live_xxx'
}
});
const data = await res.json();
console.log(data);
{
"data": [
{
"id": "cnt_uuid_abc123",
"phone": "6281234567890",
"name": "Budi",
"email": "budi@example.com",
"vars": {},
"consent": true
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 1,
"hasMore": false,
"page": 1
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope contacts:read diperlukan.",
"request_id": "req_01HZX..."
}
}
Buat Kontak
https://api.kirimkan.my.id/api/v1/contacts
Menambahkan kontak baru ke workspace.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| Content-Type | Ya | application/json | Format body request. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"Content-Type": "application/json",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| phone | string | Ya | Nomor kontak. |
| name | string | Tidak | Nama kontak. |
| string | Tidak | Email kontak. | |
| vars | object | Tidak | Variabel tambahan. |
| consent | boolean | Tidak | Persetujuan kontak. |
{
"phone": "6281234567890",
"name": "Budi",
"email": "budi@example.com",
"vars": {
"kota": "Medan"
},
"consent": true
}
Dikirim sebagai JSON body. Field opsional boleh dihilangkan.
curl -X POST https://api.kirimkan.my.id/api/v1/contacts \
-H "Authorization: Bearer wa_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "6281234567890",
"name": "Budi",
"email": "budi@example.com",
"consent": true
}'
<?php
$response = Http::withToken('wa_live_xxx')
->post('https://api.kirimkan.my.id/api/v1/contacts', [
'phone' => '6281234567890',
'name' => 'Budi',
'email' => 'budi@example.com',
'consent' => true,
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/contacts', {
method: 'POST',
headers: {
'Authorization': 'Bearer wa_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
phone: '6281234567890',
name: 'Budi',
email: 'budi@example.com',
consent: true
})
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "cnt_uuid_abc123",
"phone": "6281234567890",
"name": "Budi"
}
}
{
"error": {
"code": "validation_error",
"message": "Nomor kontak tidak valid.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "request_error",
"message": "Kontak dengan nomor ini sudah ada.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "contact_limit",
"message": "Batas kontak paket 1000 tercapai.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope contacts:write diperlukan.",
"request_id": "req_01HZX..."
}
}
Buat Campaign
https://api.kirimkan.my.id/api/v1/campaigns
Membuat campaign broadcast ke audiens tertentu.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| Content-Type | Ya | application/json | Format body request. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"Content-Type": "application/json",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| name | string | Ya | Nama campaign. |
| message | string | Ya | Isi pesan. |
| audience | object | Ya | Target penerima. |
| device_id | string | Tidak | ID perangkat pengirim. |
| scheduled_at | string | Tidak | Jadwal kirim (ISO 8601). |
| delay_min_seconds | integer | Tidak | Jeda minimum (detik). |
| delay_max_seconds | integer | Tidak | Jeda maksimum (detik). |
{
"name": "Promo Oktober",
"device_id": "dev_uuid_abc123",
"message": "Halo {name}, ada promo hari ini.",
"audience": {
"type": "manual",
"phones": [
{
"phone": "6281234567890"
}
]
}
}
Dikirim sebagai JSON body. Field opsional boleh dihilangkan.
curl -X POST https://api.kirimkan.my.id/api/v1/campaigns \
-H "Authorization: Bearer wa_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Promo Oktober",
"device_id": "dev_uuid_abc123",
"message": "Halo {name}, ada promo hari ini.",
"audience": {
"type": "manual",
"phones": [{ "phone": "6281234567890" }]
}
}'
<?php
$response = Http::withToken('wa_live_xxx')
->post('https://api.kirimkan.my.id/api/v1/campaigns', [
'name' => 'Promo Oktober',
'device_id' => 'dev_uuid_abc123',
'message' => 'Halo {name}, ada promo hari ini.',
'audience' => [
'type' => 'manual',
'phones' => [
['phone' => '6281234567890'],
],
],
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/campaigns', {
method: 'POST',
headers: {
'Authorization': 'Bearer wa_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Promo Oktober',
device_id: 'dev_uuid_abc123',
message: 'Halo {name}, ada promo hari ini.',
audience: {
type: 'manual',
phones: [{ phone: '6281234567890' }]
}
})
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "cmp_uuid_abc123",
"status": "queued",
"total_recipients": 1,
"stats": {
"pending": 1,
"queued": 0,
"sent": 0,
"failed": 0,
"skipped": 0,
"canceled": 0,
"total": 1
}
}
}
{
"error": {
"code": "validation_error",
"message": "Tidak ada penerima valid setelah filter suppression.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "feature_locked",
"message": "Fitur campaign tidak tersedia pada paket ini.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope campaigns:write diperlukan.",
"request_id": "req_01HZX..."
}
}
Status Perangkat
https://api.kirimkan.my.id/api/v1/devices
Menampilkan perangkat dan status koneksinya.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| Tidak ada parameter. | |||
{}
Tidak ada parameter dan tidak ada body.
Tidak ada parameter.
curl https://api.kirimkan.my.id/api/v1/devices \ -H "Authorization: Bearer wa_live_xxx"
<?php
$response = Http::withToken('wa_live_xxx')
->get('https://api.kirimkan.my.id/api/v1/devices');
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/devices', {
headers: {
'Authorization': 'Bearer wa_live_xxx'
}
});
const data = await res.json();
console.log(data);
{
"data": [
{
"id": "dev_uuid_abc123",
"name": "Perangkat Utama",
"phone_number": "6281234567890",
"status": "connected",
"connected": true,
"qr_available": false,
"autoread": false,
"last_seen_at": "2026-10-21T10:00:00.000Z",
"created_at": "2026-10-01T08:00:00.000Z"
}
]
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope devices:read diperlukan.",
"request_id": "req_01HZX..."
}
}
Buat Webhook
https://api.kirimkan.my.id/api/v1/webhooks
Mendaftarkan endpoint webhook baru.
| Header | Wajib | Contoh | Keterangan |
|---|---|---|---|
| Authorization | Ya | Bearer wa_live_xxx | API key Anda. Header X-API-Key juga diterima sebagai alternatif. |
| Content-Type | Ya | application/json | Format body request. |
| X-Request-Id | Tidak | req_order_1001 | ID pelacakan buatan Anda (A-Z, a-z, 0-9, _ . : -, maks. 64 karakter). Bila kosong atau tidak valid, server membuat sendiri. |
{
"Authorization": "Bearer wa_live_xxx",
"Content-Type": "application/json",
"X-Request-Id": "req_order_1001"
}
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
| url | string | Ya | URL HTTPS publik. |
| events | array | Tidak | Daftar event yang dikirim. |
{
"url": "https://example.com/webhooks/kirimkan",
"events": [
"message.status.updated",
"device.connected"
]
}
Dikirim sebagai JSON body. Field opsional boleh dihilangkan.
Secret hanya ditampilkan sekali saat pembuatan.
curl -X POST https://api.kirimkan.my.id/api/v1/webhooks \
-H "Authorization: Bearer wa_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/kirimkan",
"events": ["message.status.updated", "device.connected"]
}'
<?php
$response = Http::withToken('wa_live_xxx')
->post('https://api.kirimkan.my.id/api/v1/webhooks', [
'url' => 'https://example.com/webhooks/kirimkan',
'events' => ['message.status.updated', 'device.connected'],
]);
return $response->json();
const res = await fetch('https://api.kirimkan.my.id/api/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer wa_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com/webhooks/kirimkan',
events: ['message.status.updated', 'device.connected']
})
});
const data = await res.json();
console.log(data);
{
"data": {
"id": "wh_uuid_abc123",
"url": "https://example.com/webhooks/kirimkan",
"secret": "whsec_xxx",
"events": [
"message.status.updated",
"device.connected"
]
}
}
{
"error": {
"code": "validation_error",
"message": "Pilih minimal satu event.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "invalid_key",
"message": "API key tidak valid atau sudah dicabut.",
"request_id": "req_01HZX..."
}
}
{
"error": {
"code": "insufficient_scope",
"message": "Scope webhooks:write diperlukan.",
"request_id": "req_01HZX..."
}
}
Verifikasi Signature
Setiap permintaan webhook memiliki header X-Webhook-Signature berisi sha256=<hmac>. Verifikasi dengan body mentah (sebelum di-parse), lalu bandingkan secara constant-time.
signature = "sha256=" + HMAC_SHA256(signing_secret, raw_request_body)
Balas 2xx dengan cepat. Pengiriman ulang dilakukan bila endpoint gagal.
Kode Error
Error dikembalikan dalam bentuk berikut:
{
"error": {
"code": "validation_error",
"message": "number wajib diisi.",
"request_id": "req_01HZX..."
}
}
| HTTP | Kode | Penanganan |
|---|---|---|
| 400 | validation_error | Perbaiki payload. |
| 401 | invalid_key | Periksa API key dan status pencabutan. |
| 403 | insufficient_scope | Buat kunci dengan scope sesuai. |
| 404 | not_found | Periksa ID resource. |
| 402 | quota_exceeded | Kuota paket habis; upgrade paket. |
| 429 | rate_limited | Hormati header Retry-After. |
| 500 | internal_error | Hubungi admin dengan request ID. |
Daftar Scope
Pilih scope seminimal mungkin saat membuat API key. Daftar aktual dapat dibaca dari GET /api/v1/scopes.
- messages:send, messages:read
- devices:read, devices:write
- contacts:read, contacts:write
- campaigns:read, campaigns:write
- automation:read, automation:write
- webhooks:read, webhooks:write
- rotators:read, rotators:write
- submissions:read, submissions:write
- polls:read, polls:write
- integrations:read, integrations:write
- billing:read, reports:read