Send
Endpoint
POST https://api.kirisan.com/v1/send
Authorization: Bearer YOUR_ACCOUNT_TOKEN
Content-Type: application/json Mengirim ke satu penerima per permintaan. Untuk batch besar, gunakan Send → Campaign di dashboard atau panggil endpoint ini sekali per penerima dari aplikasi Anda.
Body permintaan
| Field | Wajib | Deskripsi |
|---|---|---|
keys | Ya | Token channel — whatsapp, telegram, waba, email |
content | Ya | Pesan per channel — ID template atau pesan inline |
target | Ya | Alamat penerima per channel + variables opsional |
context | Tidak | Penjadwalan dan perilaku pengiriman |
keys
{
"keys": {
"whatsapp": {
"token": "DEVICE_TOKEN",
"fallback": false,
"fallback_sequence": 0
},
"email": {
"token": "SENDER_TOKEN",
"fallback": true,
"fallback_sequence": 1
}
}
} Sertakan key untuk setiap channel yang akan Anda kirimi. Lihat Authentication untuk tempat menyalin token.
content
Setiap entri channel memakai salah satu template tersimpan atau pesan inline — bukan keduanya.
Referensi template (disarankan — sama seperti Send → Send):
{
"content": {
"whatsapp": { "template": 42 },
"email": { "template": 17 }
}
} Pesan inline (WhatsApp, Telegram, WABA, dan email tanpa template):
{
"content": {
"whatsapp": {
"message": {
"type": "text",
"message": "Hello {{name}}, your order is ready."
}
},
"email": {
"message": {
"type": "text",
"subject": "Promo for {{name}}",
"message": "Plain text optional",
"html": "<p>Hello {{name}}</p>"
}
}
}
} Email memakai salah satu template tersimpan atau pesan inline (subject plus message dan/atau html) — bukan keduanya. Pesan inline wajib type: "text" dan subject.
Tiga jenis email
Kirisan mengelompokkan setiap pengiriman email ke satu jenis. Anda tidak mengisi field jenis terpisah — Kirisan menentukannya dari cara Anda mengirim.
| Jenis | Kapan dipakai | Yang terjadi |
|---|---|---|
| Transactional | Template dengan Type transactional (OTP, struk, notifikasi akun) | Kirisan mengirim sekarang. Respons HTTP menunggu hasil. |
| Marketing | Template dengan Type marketing (promo, newsletter) | Kirisan menerima dulu, lalu mengirim berurutan. Respons "queued": true. |
| Raw | Pesan inline (content.email.message) tanpa template | Sama seperti marketing: diterima dulu, lalu dikirim berurutan. |
Yang perlu Anda ketahui
- Send → Send di dashboard selalu memakai template, jadi jenisnya transactional atau marketing sesuai kolom Type. Email tanpa template hanya lewat API.
- Marketing dan raw: paling banyak 2 permintaan per detik per domain (kedua jenis berbagi batas itu). Permintaan berikutnya di detik yang sama ditolak dengan
rate_limiteddanretry_after. - Template marketing hanya ke alamat yang sudah pernah menerima email dari domain ini. Alamat baru ditolak. Transactional dan raw boleh ke alamat baru.
- Kredit domain dipotong saat email benar-benar terkirim, bukan saat Kirisan menjawab
queued. - Kampanye di Send → Campaign tidak menunggu antrean API — Kirisan mengirim langsung. Jika jenis template kampanye sedang diblokir, kampanye dijeda.
Saat email-only marketing atau raw diterima:
{
"status": true,
"queued": true,
"request_id": 12345,
"channels": {
"email": { "status": true, "queued": true }
}
} queued berarti Kirisan sudah menerima permintaan. Hasil akhir muncul di Channel → Email → Logs dan, jika Anda menyiapkan webhook status kirim, di POST ke URL Anda. context.behaviour.mode tidak mengubah perilaku ini.
message.type | Channel | Catatan |
|---|---|---|
text | WhatsApp, Telegram, WABA | Teks biasa (WABA: aturan sesi berlaku). Tombol Telegram dipasang di sini lewat richContext.buttons. |
image, video, document | WhatsApp, Telegram, WABA | Memerlukan richContext.fileUrl atau richContext.fileId. Telegram boleh sekaligus menyertakan tombol. |
location | WhatsApp, Telegram | Memerlukan richContext.location — teks message diabaikan |
interactive | WABA | Tombol balas sesi atau daftar — lihat Tombol. Bukan untuk Telegram (pakai text + buttons). |
message.richContext (opsional):
| Field | Tujuan |
|---|---|
fileUrl | URL HTTPS publik ke lampiran |
fileId | ID file yang diunggah ke Resources → Files |
fileName | Nama tampilan — Kirisan dapat menambahkan ekstensi yang terdeteksi |
footer | Teks footer (jika didukung) |
location | { "lat", "lng", "name", "address" } untuk pesan lokasi |
buttons | Baris tombol — bentuknya tergantung channel (lihat Tombol) |
listMessage | Objek daftar WABA (label button + sections) |
Tombol
Kirisan tidak menganggap “tombol” sebagai satu tipe universal. Channel dan jalur pesan menentukan jenis yang bisa dikirim.
Telegram — keyboard inline (url / callback / copy)
Pakai type: "text" (atau media) dengan richContext.buttons sebagai array baris. Setiap tombol butuh text dan type:
type | Field tambahan | Perilaku |
|---|---|---|
url | url | Membuka tautan (http / https / tg://) |
callback | callbackData | Mengirim callback ke bot Anda (maks. 64 byte) |
copy | copyText | Menyalin teks ke clipboard pengguna |
{
"type": "text",
"message": "Choose an option:",
"richContext": {
"buttons": [
[
{ "text": "Open site", "type": "url", "url": "https://example.com" },
{ "text": "Confirm", "type": "callback", "callbackData": "confirm" }
],
[
{ "text": "Copy code", "type": "copy", "copyText": "PROMO-10" }
]
]
}
} Tiga jenis yang sama tersedia saat Anda membuat keyboard di Channel → Telegram → Templates.
WABA — interaktif sesi (tombol balas atau daftar)
Pesan WABA bebas / free-form (termasuk interaktif) tidak membutuhkan template Meta, tetapi hanya jalan di dalam jendela customer care / sesi Meta — biasanya setelah pengguna mengirim pesan ke Anda (aturan sama dengan teks dan media bebas). Di luar jendela itu, Meta menolak kiriman free-form; pakai template yang sudah disetujui.
Saat sesi terbuka, type: "interactive" menerima:
- Tombol balas —
richContext.buttonsdenganid+textsaja (maks. 3 total; tombolreplyMeta). Tidak perlu template. - Daftar —
richContext.listMessagedengan labelbuttondansections/rows. Tidak perlu template.
Tidak tersedia di jalur free-form ini: tombol gaya template quick reply, URL, atau call.
{
"type": "interactive",
"message": "Need help with order {{order_id}}?",
"richContext": {
"footer": "Reply anytime",
"buttons": [[{ "id": "yes", "text": "Yes" }, { "id": "no", "text": "No" }]]
}
} WABA — template Meta (quick reply / URL / call)
Pakai template bila Anda perlu mengirim di luar jendela sesi, atau bila Anda butuh tombol quick reply / URL / call.
Ketiga jenis tombol itu ada di template yang disetujui Meta, bukan di JSON interactive inline. Buat di Channel → WABA → Templates, lalu kirim dengan content.waba.template: <id>.
| Tombol template | Tipe Meta | Catatan |
|---|---|---|
| Quick reply | quick_reply | Pengguna mengetuk → Anda menerima payload balasan |
| URL | url | Membuka tautan; boleh satu {{variable}} |
| Call | phone_number | Memulai panggilan telepon |
| Jalur | Butuh template disetujui? | Jendela sesi? | Jenis tombol |
|---|---|---|---|
interactive free-form | Tidak | Wajib (jendela terbuka) | Balas (id/text) atau daftar |
content.waba.template | Ya | Tidak wajib | Quick reply / URL / call (sesuai template) |
Header media dinamis (gambar / video / dokumen)
Template dengan header IMAGE, VIDEO, atau DOCUMENT memerlukan media saat kirim (aturan Meta). Saat buat template, Anda mengunggah contoh untuk persetujuan Meta — contoh itu tidak harus dipakai setiap kirim.
Saat POST /v1/send dengan content.waba.template, kirim URL publik di target.variables. Nilai dari API menggantikan contoh statis template untuk pesan itu:
| Header template | Key di target.variables |
|---|---|
| Gambar | default_image_url |
| Video | default_video_url |
| Dokumen | default_file_url |
Variabel body/header teks ({{name}}, dll.) tetap di map variables yang sama.
{
"keys": { "waba": "TOKEN_DEVICE_WABA" },
"content": { "waba": { "template": 42 } },
"target": {
"waba": "6281234567890",
"variables": {
"customer_name": "Budi",
"default_image_url": "https://cdn.example.com/promo.jpg"
}
}
} URL harus bisa diambil server Meta — HTTPS langsung ke file (CDN, hosting, bucket). Link share Google Drive biasa, halaman login, atau redirect panjang sering gagal. Format dan ukuran file harus memenuhi batas Meta.
Jika template wajib header media tetapi URL tidak ada (dan tidak ada fallback dari template), kirim gagal — lihat pesan channel di respons atau Errors.
Contoh interaktif di bagian Contoh di bawah: Template WABA — header gambar dinamis.
WhatsApp (device Fonnte) tidak mendukung tombol interaktif outbound di /v1/send.
target
{
"target": {
"whatsapp": "6281234567890",
"email": "customer@example.com",
"telegram": "123456789",
"waba": "6281234567890",
"variables": {
"name": "Alex",
"order_id": "A-1001"
}
}
} | Field | Format |
|---|---|
whatsapp, waba | Nomor telepon dengan kode negara (digit, tanpa + juga boleh) |
telegram | Chat ID |
email | Alamat email valid |
variables | Mengganti {{placeholder}} di template dan pesan inline sebelum send. Untuk WABA header media: default_image_url, default_video_url, atau default_file_url (lihat di atas). |
Abaikan field channel yang tidak Anda kirimi. Setiap channel aktif di content memerlukan target yang cocok (kecuali difilter oleh context.behaviour.channel).
context
{
"context": {
"timing": {
"schedule": 1735689600
},
"behaviour": {
"channel": "all",
"mode": "sync"
}
}
} | Field | Arti |
|---|---|
timing.schedule | Timestamp Unix (detik) — antre untuk pengiriman di masa depan. Abaikan atau set null untuk kirim sekarang. Waktu lampau ditolak. |
behaviour.channel | "all" (default) — kirim setiap channel yang punya key dan content. Atau salah satu dari whatsapp, telegram, waba, email untuk membatasi ke satu channel. |
behaviour.mode | "sync" (default) — tunggu hasil channel lalu kembalikan di respons HTTP. "async" — antre segera (pending di log Kirisan); hasil muncul di Logs/History otomatis. Opsional: terima POST ke webhook send_status jika Anda mengonfigurasinya. |
Saat dijadwalkan, respons menyertakan "scheduled": true dan setiap channel menampilkan "scheduled": true alih-alih mengirim segera. Penjadwalan memakai jalur terjadwal (bukan mode: async).
Contoh
Setiap contoh adalah permintaan POST /v1/send lengkap. Buka baris untuk cURL, Node.js, Python, PHP, Go, atau JSON mentah. Ganti token, ID, dan target dengan nilai Anda sendiri.
Fallback cascade
Ketika channel key memakai fallback: true, Kirisan mencoba tier secara berurutan:
- Primary — semua key tanpa fallback (dikirim bersamaan).
- Fallback 1 — key dengan
fallback_sequence: 1(paralel dalam tier). - Fallback 2 — key dengan
fallback_sequence: 2, dan seterusnya.
Segera setelah channel apa pun dalam tier berhasil, tier berikutnya dilewati. Ini sama dengan Use as fallback dan Sequence di Send → Send. Lihat Send messages untuk panduan dashboard.
Channel yang gagal di tier sebelumnya tetap muncul di bawah "channels" dengan "reason". Channel fallback yang berhasil dapat menyertakan "fallback": true.
Respons
Send langsung (mode: sync atau dihilangkan):
{
"status": true,
"id": 98765,
"request_id": 12345,
"channels": {
"whatsapp": {
"status": true,
"id": 98765,
"processing_time": "142ms"
}
}
} id adalah send.id (integer, sumber utama untuk pelacakan di Kirisan). request_id adalah send_log.id untuk permintaan /v1/send ini. id dihilangkan jika belum ada baris send (misalnya diblokir sebelum channel dipanggil).
Async (mode: async) — diterima ke antrean:
{
"status": true,
"queued": true,
"request_id": 12345
} Message id belum ada saat antre — hasil akhir tersimpan otomatis di log Kirisan (send / send_log). Jika Anda mengonfigurasi webhook send_status, payload yang sama juga di-POST ke URL Anda.
Kegagalan sebagian:
{
"status": false,
"channels": {
"whatsapp": {
"status": false,
"reason": "Device disconnected",
"processing_time": "89ms"
},
"email": {
"status": true,
"fallback": true,
"processing_time": "891ms"
}
}
} Terjadwal:
{
"status": true,
"scheduled": true,
"channels": {
"telegram": { "status": true, "scheduled": true }
}
} status tingkat atas | Arti |
|---|---|
true | Minimal satu channel terkirim atau dijadwalkan, atau permintaan async berhasil diantrekan |
false | Setiap channel yang dicoba gagal, atau validasi memblokir permintaan |
Baca "reason" di root untuk error validasi. Baca "channels.<name>.reason" untuk kegagalan pengiriman. Lihat Errors.
Kirisan juga menyimpan request + response ke audit log untuk kegagalan validasi/auth (JSON tidak valid, token salah, content salah, dll.) — respons menyertakan request_id bila log berhasil ditulis, agar dukungan bisa menelusuri permintaan Anda.
Catatan channel
| Channel | message inline | Template |
|---|---|---|
| Ya — teks, media, lokasi (tanpa tombol interaktif) | Ya — harus disetujui dan aktif | |
| Telegram | Ya — teks/media + keyboard inline (url / callback / copy) | Ya — jenis tombol yang sama di editor template |
| WABA | Ya — teks, media, tombol balas interaktif atau daftar (jendela sesi) | Ya — template Meta dengan quick reply / URL / call; kelola di Channel → WABA → Templates |
Ya — subject plus message dan/atau html (type: "text") | Ya — buat di Channel → Email → Templates |
Template yang direferensikan via ID harus Approved dan Active. Daftar ID lewat Templates API (GET /v1/templates), salin dari Channel → channel → Templates, atau gunakan konten message inline.
Terkait
- Authentication — token akun dan channel key
- Templates API — daftar dan ambil template
- Errors — kode HTTP dan alasan umum
- Send status webhook — hasil async
POST /v1/send - Send messages — bentuk permintaan yang sama dari UI
- Email templates — Type transactional vs marketing
- WhatsApp templates — buat template dan salin ID untuk send