Langsung ke konten

Pesan masuk

4 min read

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:

FieldTipeArti
eventstringSelalu incoming_message
devicestringToken/nomor device chat, atau alamat email penerima
channelstringwhatsapp, telegram, waba, atau email
senderobjectPengirim pesan — lihat di bawah
messageobjectIsi pesan — lihat di bawah
metadataobjectField tambahan khusus channel
timestampintegerDetik Unix
productionbooleantrue untuk lalu lintas live; false untuk Webhooks → Test

sender

FieldArti
senderTarget balasan — telepon WhatsApp/WABA, chat id Telegram, atau alamat From email
nameNama tampilan setelah normalisasi (gunakan untuk {{name}})
detailsObjek khusus channel — lihat bagian per channel

message

FieldArti
typetext, image, video, document, location, callback, button_reply, list_reply, dan tipe media lain
textBaris utama — body, caption, atau data callback (gunakan untuk {{message}})
fileOpsional — url, filename, filetype, mime_type, file_id
locationOpsional — latitude, longitude, coordinate
buttonOpsional — 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.fileArti
urlPresigned GET berumur pendek (Cloudflare R2). Berlaku sekitar 24 jam sejak pengiriman — unduh segera.
filenameNama tampilan asli (misalnya invoice.pdf)
filetypeJenis kasar: image, video, audio, atau file
mime_typeTipe MIME jika diketahui (misalnya application/pdf)
file_idId 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