Bahasa Indonesia
Terima Pesan (Webhook)
Kirim pesan udah bisa, sekarang giliran nerima. Pasang webhook, terus Zate bakal ngabarin server kamu tiap ada pesan baru, pesan diedit, pesan dihapus, atau pesan dibaca di chat pribadi akun kamu. Cocok buat auto-reply, customer service, atau sekadar nyatet obrolan.
Siapin Endpoint Penerima
Bikin endpoint HTTP di server kamu yang nerima POST dengan body JSON. Zate ngirim token kamu di header x-token, jadi cocokin dulu sebelum diproses:
js
// webhook.mjs, pakai Express
import express from 'express';
const app = express();
app.use(express.json());
const handled = new Set(); // Di produksi, simpan di Redis atau database
app.post('/webhook/zate', (req, res) => {
if (req.header('x-token') !== process.env.ZATE_WEBHOOK_TOKEN) {
return res.sendStatus(401);
}
// Jawab secepatnya: Zate cuma nunggu 10 detik
res.sendStatus(200);
const event = req.body;
// Event yang sama bisa kekirim dua kali, lewatin yang udah pernah diproses
if (handled.has(event.eventId)) return;
handled.add(event.eventId);
if (event.type === 'message' && !event.data.fromMe) {
console.log(`${event.data.user.name}: ${event.data.text}`);
}
});
app.listen(3000);Pasang Webhook-nya
Panggil Atur Webhook dengan URL endpoint tadi dan token rahasia buatan kamu sendiri:
bash
curl -X PUT "https://api-zate.azickri.com/session/webhook" \
-H "id: $ZATE_ID" \
-H "session-id: $ZATE_SESSION_ID" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/webhook/zate","token":"rahasia-banget-123"}'Mulai detik itu, event baru langsung dikirim ke URL kamu. Pesan sebelum webhook dipasang nggak ikut dikirim. Buat matiin webhook, kirim url dan token kosong.
Bikin token yang susah ditebak
Misalnya hasil openssl rand -hex 16. Token ini satu-satunya cara server kamu tahu request-nya beneran dari Zate, dan dia ikut di setiap request, jadi pakai https kalau URL-nya lewat internet.
Coba Kirim Pesan
Minta temen kirim pesan ke akun kamu (atau kirim dari akun lain). Dalam hitungan detik, server kamu nerima event kayak gini:
json
{
"eventId": "68b3f0a2c1d4e5f6a7b8c9d0:message:1024",
"type": "message",
"id": "68b3f0a2c1d4e5f6a7b8c9d0",
"generatedId": "123456789",
"data": {
"chatType": "private",
"chatId": "111222333",
"messageId": "1024",
"fromMe": false,
"user": {
"id": "111222333",
"name": "Budi",
"username": "budi",
"phone": "",
"isBot": false,
"isContact": true,
"picture": "https://api-zate.azickri.com/media/68b3f0a2c1d4e5f6a7b8c9d0/111222333/5123456789012345678/profile/c2inRmxRIRLbgqB1x_4xXh.jpg"
},
"type": "text",
"text": "Cak, sate ayam 20 tusuk ya",
"replyToMessageId": "",
"created": "2026-10-12T12:00:00.000Z"
},
"createdAt": "2026-10-12T12:00:00.120Z"
}Isi Event
Semua event bungkusnya sama:
| Kolom | Tipe | Keterangan |
|---|---|---|
eventId | string | Pengenal event. Event yang sama selalu punya eventId yang sama, jadi pakai ini buat ngelewatin duplikat. |
type | string | Jenis event, lihat tabel di bawah. |
id | string | id sesi Zate, sama kayak header id. Berguna kalau satu endpoint nerima event dari beberapa sesi. |
generatedId | string | ID user Telegram dari akun yang login. |
data | object | Isi event, bentuknya tergantung type. |
createdAt | string | Waktu Zate bikin event ini (ISO 8601). |
type | Kapan dikirim | data |
|---|---|---|
message | Ada pesan masuk, atau akun kamu kirim pesan dari perangkat lain | Objek pesan |
message.edit | Pesan diedit. Reaksi (emoji) bukan edit, jadi nggak dikirim | Objek pesan plus edited |
message.delete | Pesan dihapus | { messageIds } |
message.read | Pesan dibaca | { chatType, chatId, messageId, byMe } |
Objek Pesan
data buat message dan message.edit:
| Kolom | Tipe | Keterangan |
|---|---|---|
chatType | string | Selalu private. |
chatId | string | ID user lawan bicara. Pakai ini sebagai user di Kirim Pesan buat bales. |
messageId | string | ID pesan. |
fromMe | boolean | true kalau pesannya dikirim akun kamu sendiri dari perangkat lain (HP, Telegram Desktop). |
user | object | Lawan bicara, lihat objek user. Selalu orang lain, walaupun fromMe: true. |
type | string | text, image, video, audio, document, sticker, location, contact, poll, atau unsupported. |
text | string | Isi pesan, atau caption buat media. |
replyToMessageId | string | ID pesan yang dibales. Kosong kalau bukan balasan. |
image | object | Kalau type = image: url, thumbnail, mimetype. |
video | object | Kalau type = video: url, thumbnail, duration (detik), mimetype. |
audio | object | Kalau type = audio: url, duration (detik), mimetype, isVoice (true buat voice note). |
document | object | Kalau type = document: url, name, size (byte), mimetype. |
sticker | object | Kalau type = sticker: url, mimetype (image/webp). |
location | object | Kalau type = location: latitude, longitude, name, address. |
contact | object | Kalau type = contact: name, phone. |
polling | object | Kalau type = poll: name (pertanyaan) dan options (daftar pilihan). |
created | string | Waktu pesan dikirim (ISO 8601). |
edited | string | Cuma di message.edit: waktu pesan diedit. |
Semua url dan thumbnail media itu link media publik. Nggak ada yang diunduh sampai link-nya dibuka. Stiker animasi pakai gambar thumbnail-nya biar bisa tampil di tag <img>.
Objek user
| Kolom | Tipe | Keterangan |
|---|---|---|
id | string | ID user Telegram, sama kayak chatId. |
name | string | Nama tampilan. |
username | string | Username tanpa @. Kosong kalau nggak punya. |
phone | string | Nomor HP. Kosong kecuali orangnya ngebagiin nomor ke akun kamu. |
isBot | boolean | true kalau lawan bicaranya bot. |
isContact | boolean | true kalau orangnya ada di kontak kamu. |
picture | string | Link publik foto profil kecil. Kosong kalau nggak ada fotonya atau disembunyiin privasinya. Foto baru = link baru. |
Event Lainnya
json
{
"eventId": "68b3f0a2c1d4e5f6a7b8c9d0:message.edit:1024:1791806460",
"type": "message.edit",
"id": "68b3f0a2c1d4e5f6a7b8c9d0",
"generatedId": "123456789",
"data": {
"chatType": "private",
"chatId": "111222333",
"messageId": "1024",
"fromMe": false,
"user": { "id": "111222333", "name": "Budi", "username": "budi", "phone": "", "isBot": false, "isContact": true, "picture": "" },
"type": "text",
"text": "Cak, sate ayam 30 tusuk ya",
"replyToMessageId": "",
"created": "2026-10-12T12:00:00.000Z",
"edited": "2026-10-12T12:01:00.000Z"
},
"createdAt": "2026-10-12T12:01:00.090Z"
}json
{
"eventId": "68b3f0a2c1d4e5f6a7b8c9d0:message.delete:5821",
"type": "message.delete",
"id": "68b3f0a2c1d4e5f6a7b8c9d0",
"generatedId": "123456789",
"data": {
"messageIds": ["1024", "1025"]
},
"createdAt": "2026-10-12T12:02:00.050Z"
}json
{
"eventId": "68b3f0a2c1d4e5f6a7b8c9d0:message.read:out:111222333:1026",
"type": "message.read",
"id": "68b3f0a2c1d4e5f6a7b8c9d0",
"generatedId": "123456789",
"data": {
"chatType": "private",
"chatId": "111222333",
"messageId": "1026",
"byMe": false
},
"createdAt": "2026-10-12T12:03:00.070Z"
}message.deletenggak nyebut chat-nya, soalnya Telegram emang nggak ngasih tahu buat chat pribadi. Tenang, ID pesan pribadi itu unik per akun. Penghapusan di grup biasa (basic group) kadang ikut kekirim juga, jadi ID yang nggak kamu kenal boleh dicuekin.message.readartinya semua pesan sampaimessageIdudah dibaca.byMe: trueberarti akun kamu yang baca chat orang itu,byMe: falseberarti orang itu yang baca pesan dari kamu.
Bales Otomatis
chatId bisa langsung dipakai sebagai user buat bales:
js
async function balas(chatId, text) {
await fetch('https://api-zate.azickri.com/message', {
method: 'POST',
headers: {
'id': process.env.ZATE_ID,
'session-id': process.env.ZATE_SESSION_ID,
'Content-Type': 'application/json',
},
body: JSON.stringify({ user: chatId, type: 'text', text }),
});
}
// Di dalam handler webhook
if (event.type === 'message' && !event.data.fromMe && !event.data.user.isBot) {
await balas(event.data.chatId, 'Siap, pesanan lagi dibakar! 🔥');
}Jangan bales pesan sendiri
Selalu cek fromMe. Pesan yang kamu kirim dari HP juga masuk sebagai event message dengan fromMe: true, dan ngebales itu bisa bikin obrolan muter-muter sendiri. Pesan yang dikirim lewat Kirim Pesan sendiri nggak dikirim ke webhook, soalnya response-nya udah ngasih messageId.
Pengiriman dan Retry
- Event dikirim satu per satu per akun, sesuai urutan Zate nerimanya. Kalau urutan penting banget, urutin pakai
created. - Response
2xxdianggap berhasil. Zate nunggu jawaban maksimal 10 detik. - Error jaringan, timeout,
429, dan5xxdicoba ulang setelah 2 detik, 10 detik, lalu 30 detik. Kalau masih gagal, event-nya dibuang. 4xxlainnya (misalnya401karena token salah) nggak dicoba ulang, soalnya ngirim ulang juga nggak bakal ngubah apa-apa.- Maksimal 1.000 event ngantre per akun. Kalau lebih, yang paling lama dibuang duluan.
- Retry atau susulan pesan bisa ngirim event yang sama dua kali. Lewatin
eventIdyang udah pernah kamu proses.
Pesan yang Kelewat
Zate nyimpen posisi update terakhir tiap akun. Tiap kali nyambung lagi, entah habis server restart atau koneksi sempat putus, Zate nanya ke Telegram apa aja yang kelewat dan nyusulin event-nya ke webhook kamu.
- Webhook yang baru dinyalain mulai dari detik itu. Histori sebelumnya nggak dikirim.
- Reset Session atau login ulang juga mulai dari awal lagi.
- Habis downtime yang lama, pesan susulan bisa udah berjam-jam umurnya. Kalau kamu bikin auto-reply, cek
createddulu biar nggak bales pesan basi.
Yang Nggak Dikirim
- Pesan di grup dan channel. Webhook cuma buat chat pribadi.
- Saved Messages, alias chat akun kamu sama dirinya sendiri.
- Pesan layanan, misalnya notifikasi screenshot atau "bergabung ke Telegram".
- Reaksi emoji.
- Pesan yang dikirim lewat Kirim Pesan.