Pesan masuk
Event incoming_message aktif saat pelanggan mengirim pesan ke device chat yang terhubung ke webhook Anda, atau saat email diterima untuk alamat pengirim email yang tertaut.
Header:
X-Kirisan-Event: incoming_message Envelope terpadu
WhatsApp, Telegram, WABA, dan Email berbagi bentuk tingkat atas yang sama:
| Field | Tipe | Arti |
|---|---|---|
event | string | Selalu incoming_message |
device | string | Token/nomor device chat, atau alamat email penerima |
channel | string | whatsapp, telegram, waba, atau email |
sender | object | Pengirim pesan — lihat di bawah |
message | object | Isi pesan — lihat di bawah |
metadata | object | Field tambahan khusus channel |
timestamp | integer | Detik Unix |
production | boolean | true untuk lalu lintas live; false untuk Webhooks → Test |
sender
| Field | Arti |
|---|---|
sender | Target balasan — telepon WhatsApp/WABA, chat id Telegram, atau alamat From email |
name | Nama tampilan setelah normalisasi (gunakan untuk {{name}}) |
details | Objek khusus channel — lihat bagian per channel |
message
| Field | Arti |
|---|---|
type | text, image, video, document, location, callback, button_reply, list_reply, dan tipe media lain |
text | Baris utama — body, caption, atau data callback (gunakan untuk {{message}}) |
file | Opsional — url, filename, filetype, mime_type, file_id |
location | Opsional — latitude, longitude, coordinate |
button | Opsional — id dan text untuk balasan tombol/daftar |
Shortcut {{…}} lainnya: Resources → Variables → Incoming. Tur dashboard: Variables.
Contoh WhatsApp
{
"event": "incoming_message",
"device": "your-whatsapp-device-token",
"channel": "whatsapp",
"sender": {
"sender": "6281234567890",
"name": "Ada",
"details": {
"type": "personal",
"sender": "6281234567890",
"pushname": "Ada",
"from_me": false
}
},
"message": {
"type": "text",
"text": "Hi, I need help with my order."
},
"metadata": {
"inboxid": 0,
"isgroup": false,
"isforwarded": false
},
"timestamp": 1735689600,
"production": true
} sender.details WhatsApp mungkin juga menyertakan senderlid, member, memberlid, dan type: "group" untuk obrolan grup.
Pesan media mengatur message.type ke image, video, audio, atau file dan mengisi message.file.url.
Contoh Telegram
{
"event": "incoming_message",
"device": "your-telegram-bot-token",
"channel": "telegram",
"sender": {
"sender": "-1001234567890",
"name": "Alex",
"details": {
"type": "group",
"chat_id": "-1001234567890",
"user_id": "555444333",
"username": "alex_test",
"first_name": "Alex",
"last_name": "",
"from_me": false
}
},
"message": {
"type": "text",
"text": "Hello from the group."
},
"metadata": {
"update_id": 100002,
"message_id": "1001",
"chat_type": "supergroup"
},
"timestamp": 1735689600,
"production": true
} Untuk query callback (ketukan tombol inline), message.type adalah callback dan message.text berisi data callback. metadata.callback_query_id mungkin ada.
Di grup, sender.sender adalah chat id (target balasan), bukan user id.
Contoh WABA
WABA menggunakan envelope yang sama dengan WhatsApp dan Telegram:
{
"event": "incoming_message",
"device": "your-waba-device-token",
"channel": "waba",
"sender": {
"sender": "6281234567890",
"name": "Ada",
"details": {
"type": "personal",
"sender": "6281234567890",
"from_me": false
}
},
"message": {
"type": "text",
"text": "Hello — WABA text message."
},
"metadata": {
"message_id": "wamid.HBgLNjI4...",
"waba_type": "text"
},
"timestamp": 1735689600,
"production": true
} Balasan interaktif menggunakan message.type button_reply atau list_reply dengan objek message.button. metadata mungkin menyertakan interactive_type, button_reply_id, atau list_reply_id.
Contoh Email
Email memakai envelope yang sama. device adalah alamat penerima (pengirim terdaftar Anda). sender.sender adalah alamat From.
{
"event": "incoming_message",
"device": "support@example.com",
"channel": "email",
"sender": {
"sender": "alice@example.com",
"name": "Alice",
"details": {
"type": "personal",
"from": "alice@example.com",
"to": "support@example.com",
"from_me": false
}
},
"message": {
"type": "text",
"text": "Hi, I need help with my order."
},
"metadata": {
"inbound_id": 42,
"subject": "Order question",
"status": "accepted_inbox",
"to": "support@example.com"
},
"timestamp": 1735689600,
"production": true
} metadata.subject berisi subjek email. metadata.status adalah accepted_inbox atau accepted_spam. Jika lampiran disimpan, file pertama muncul di message.file dan daftar lengkap di metadata.attachments.
Lampiran dan mengunduh file
Saat paket channel menyertakan lampiran dan kuota penyimpanan aktif, Kirisan menyimpan media masuk ke perpustakaan Files dan menempatkan tautan unduhan pada payload webhook.
Field message.file | Arti |
|---|---|
url | Presigned GET berumur pendek (Cloudflare R2). Berlaku sekitar 24 jam sejak pengiriman — unduh segera. |
filename | Nama tampilan asli (misalnya invoice.pdf) |
filetype | Jenis kasar: image, video, audio, atau file |
mime_type | Tipe MIME jika diketahui (misalnya application/pdf) |
file_id | Id baris Files Kirisan setelah disimpan (string). Jika storage/paket tidak mengizinkan penyimpanan, Telegram mungkin hanya mengekspos file id provider dan tanpa url host Kirisan. |
Tanpa storage aktif (atau paket yang mendukung lampiran), WhatsApp mungkin tetap menyertakan url provider/CDN; Telegram sering hanya punya metadata tanpa URL unduhan Kirisan.
Contoh payload (dokumen PDF)
{
"event": "incoming_message",
"device": "your-telegram-device-token",
"channel": "telegram",
"sender": {
"sender": "357496317",
"name": "Ada",
"details": {
"type": "personal",
"chat_id": "357496317",
"user_id": "357496317",
"username": "ada",
"first_name": "Ada",
"last_name": "",
"from_me": false
}
},
"message": {
"type": "document",
"text": "Berikut invoice-nya",
"file": {
"url": "https://….r2.cloudflarestorage.com/…/object-key?X-Amz-Algorithm=AWS4-HMAC-SHA256&…",
"filename": "invoice.pdf",
"filetype": "file",
"mime_type": "application/pdf",
"file_id": "1842"
}
},
"metadata": {
"update_id": 609668173,
"message_id": "110",
"chat_type": "private"
},
"timestamp": 1735689600,
"production": true
} Email dengan beberapa lampiran: gunakan message.file untuk file pertama, dan metadata.attachments[] (masing-masing dengan url, filename, mime_type, file_id) untuk daftar lengkap.
Mengunduh lampiran
Perlakukan message.file.url sebagai HTTPS GET biasa. Tidak perlu token API Kirisan — tanda tangan ada di query string. Simpan body respons memakai filename (atau nama yang Anda pilih).
cURL
# $URL = message.file.url dari JSON webhook
# $NAME = message.file.filename (cadangan: attachment.bin)
curl -fsSL -o "$NAME" "$URL" Node.js
import { writeFile } from 'node:fs/promises';
async function downloadIncomingFile(payload) {
const file = payload?.message?.file;
const url = String(file?.url || '').trim();
if (!url) throw new Error('No message.file.url — check plan attachments and storage quota');
const name = String(file.filename || 'attachment.bin').replace(/[/\]/g, '_');
const res = await fetch(url);
if (!res.ok) throw new Error(`Download failed: HTTP ${res.status}`);
const buf = Buffer.from(await res.arrayBuffer());
await writeFile(name, buf);
return { name, bytes: buf.length, mime: file.mime_type, fileId: file.file_id };
} Python
import pathlib
import requests
def download_incoming_file(payload: dict) -> pathlib.Path:
file = (payload.get("message") or {}).get("file") or {}
url = (file.get("url") or "").strip()
if not url:
raise ValueError("No message.file.url — check plan attachments and storage quota")
name = (file.get("filename") or "attachment.bin").replace("/", "_").replace("\", "_")
r = requests.get(url, timeout=60)
r.raise_for_status()
path = pathlib.Path(name)
path.write_bytes(r.content)
return path Jika GET mengembalikan 403 atau 404, URL presigned kemungkinan sudah kedaluwarsa — simpan salinan saat webhook pertama diterima, atau buka lagi file tersebut dari Resources → Files di dashboard.
Terkait
- Ringkasan webhook — penyiapan dan aturan pengiriman
- Verifikasi — header dan signing secret
- Payload submission — penyelesaian formulir autoreply
- Status pesan — tanda terima pengiriman WABA
- Files — perpustakaan dan batas ukuran
- Webhooks → Test — pratinjau JSON sampel per channel