Kontrak diperiksa berdasarkan kode pada 24 Oktober 2026. Dokumen ini menjelaskan implementasi yang tersedia, bukan rencana. Untuk konfigurasi melalui antarmuka, lihat panduan pengguna.
Dua arah permintaan
| Arah | Pemanggil | Alamat | Tujuan |
|---|---|---|---|
| API pengelolaan lokal | Skrip lokal → Deskgram | http://127.0.0.1:5000/api/webhooks | Mengatur endpoint dan memeriksa pengiriman |
| Webhook keluar | Deskgram → penerima Anda | URL pada endpoint | Mengirim peristiwa dengan POST JSON |
Host dan port adalah contoh backend lokal; gunakan alamat instalasi Anda. Ini bukan API lisensi, server MCP, atau metode setWebhook/getUpdates Telegram Bot API.
Rute REST ini tidak melakukan pemeriksaan Bearer tersendiri. Gunakan lingkungan lokal tepercaya; jangan membuka port backend ke internet untuk webhook keluar. Pengiriman tidak membutuhkan koneksi masuk ke komputer Deskgram. Jika ada gateway autentikasi sendiri, atur secara terpisah.
Respons lokal menggunakan JSON. Sertakan Content-Type: application/json saat mengirim pengaturan melalui POST/PUT.
Mulai cepat API
Contoh curl memakai shell yang mendukung tanda kutip tunggal. Di PowerShell, gunakan curl.exe dan aturan versi shell untuk argumen JSON. Domain, ID, dan rahasia bersifat fiktif. Teks Rusia dalam contoh hanya nilai ilustrasi, bukan nilai wajib.
- Buat endpoint nonaktif untuk memeriksa konfigurasi sebelum pengiriman otomatis:
curl -X POST 'http://127.0.0.1:5000/api/webhooks/endpoints' \ -H 'Content-Type: application/json' \ --data '{"name":"CRM: рассылка","url":"https://receiver.example.com/deskgram","secret":"YOUR_SHARED_SECRET","events":["message.sent","message.failed","lead.reply_received"],"module_filter":["spam_pm"],"payload_template":"deskgram","enabled":false}'- Ambil endpoint.id dari respons. Untuk contoh ID 12, kirim pengujian:
curl -X POST 'http://127.0.0.1:5000/api/webhooks/endpoints/12/test'- Periksa success, delivery.responsestatuscode, delivery.response_body, dan penerimaan sesungguhnya. Pengujian tidak memuat lead nyata sehingga bisa ditolak validasi bisnis CRM.
- Aktifkan melalui antarmuka atau kirim pengaturan lengkap menggunakan PUT dengan enabled: true. PUT bukan pembaruan sebagian.
- Lakukan tindakan nyata yang sesuai dengan peristiwa, lalu periksa riwayat:
curl 'http://127.0.0.1:5000/api/webhooks/deliveries?endpoint_id=12&limit=20'Objek endpoint
Bidang pembuatan dan pembaruan
POST dan PUT menggunakan model yang sama.
| Bidang | Tipe | Bawaan | Aturan |
|---|---|---|---|
name | string | Wajib | 1–120 karakter sebelum spasi tepi dihapus; gunakan nama tidak kosong |
url | string | Wajib | 8–2000 karakter, diawali http:// atau https://; HTTPS disarankan |
method | string | POST | Hanya POST |
secret | string atau null | null saat dibuat | Spasi tepi dihapus; di PUT, tidak disertakan mempertahankan, null/kosong menghapus |
headers | object bernilai string | {} | Header tambahan penerima, bukan kredensial Deskgram |
events | array string | ["task.completed"] | Enam peristiwa katalog atau "*"; daftar kosong menjadi task.completed |
module_filter | array string | [] | Kosong berarti semua modul; contoh ["spam_pm"] |
payload_template | string | deskgram | deskgram, shortresult, crmlead, custom |
payload_mapping | object | {} | Pengaturan bidang keluaran di bawah |
enabled | boolean | true | Mengizinkan pengiriman otomatis peristiwa cocok |
timeout_seconds | number | 15 | 3–60 detik |
Pada endpoint biasa, timeout berlaku untuk operasi jaringan klien HTTP, bukan batas total ketat panggilan lokal. Test dan retry menunggu pengiriman selesai, termasuk percobaan otomatis dan jeda.
Nama modul menjadi huruf kecil dan - diganti _. Entri peristiwa/modul duplikat dihapus. "*" mencakup peristiwa yang benar-benar masuk mekanisme ini, bukan menambahkan integrasi yang belum dimiliki modul lain.
Bidang respons
Selain pengaturan, tersedia id integer, hassecret boolean, createdat dan updated_at dalam UTC. secret selalu null, sekalipun rahasia tersimpan.
REST API lokal mengembalikan nilai headers tanpa penyamaran. Nilainya dapat memuat token penerima; jangan membagikan respons lengkap dalam log publik atau pesan dukungan.
Contoh respons pembuatan:
{ "success": true, "endpoint": { "id": 12, "name": "CRM: рассылка", "url": "https://receiver.example.com/deskgram", "method": "POST", "secret": null, "has_secret": true, "headers": {}, "events": ["message.sent", "message.failed", "lead.reply_received"], "module_filter": ["spam_pm"], "payload_template": "deskgram", "payload_mapping": {}, "enabled": false, "timeout_seconds": 15.0, "created_at": "2026-10-15T10:00:00Z", "updated_at": "2026-10-15T10:00:00Z" }}Metode API
Semua jalur menyertakan /api. Operasi selesai menggunakan HTTP 200, termasuk membuat dan menghapus. endpointid dan deliveryid adalah ID integer catatan.
GET /api/webhooks/endpoints
Daftar diurutkan berdasarkan waktu pembuatan, terbaru dahulu, tanpa parameter paginasi. Respons: {"endpoints": [...]} berisi objek endpoint. Daftar kosong: {"endpoints": []}.
POST /api/webhooks/endpoints
Membuat endpoint dengan model di atas. Respons: {"success": true, "endpoint": {...}}.
Tanpa enabled, endpoint langsung aktif. Kirim false secara eksplisit saat pengaturan awal.
PUT /api/webhooks/endpoints/{endpoint_id}
Memperbarui endpoint. Wajib menyertakan name, url, dan semua pengaturan yang hendak dipertahankan. Bidang yang tidak disertakan kembali ke bawaan, kecuali secret.
Jangan langsung mengirim ulang objek respons: secret: null akan menghapus rahasia tersimpan. Hilangkan seluruh kunci secret untuk mempertahankannya. Null atau string kosong eksplisit menghapusnya.
Contoh mengaktifkan sambil mempertahankan rahasia:
{ "name": "CRM: рассылка", "url": "https://receiver.example.com/deskgram", "method": "POST", "headers": {}, "events": ["message.sent", "message.failed", "lead.reply_received"], "module_filter": ["spam_pm"], "payload_template": "deskgram", "payload_mapping": {}, "enabled": true, "timeout_seconds": 15}Respons: {"success": true, "endpoint": {...}}. Endpoint tidak ditemukan: HTTP 404.
DELETE /api/webhooks/endpoints/{endpoint_id}
Menghapus endpoint tanpa badan permintaan. Respons: {"success": true, "endpoint_id": 12}. Jika tidak ada, HTTP 404.
Riwayat tetap ada. Penghapusan tidak membatalkan pengiriman yang sudah berjalan; catatan tidak dapat dicoba ulang setelah endpoint dihapus.
POST /api/webhooks/endpoints/{endpoint_id}/test
Mengirim pengujian hanya ke endpoint tersebut. Tidak memerlukan badan dan tidak menerima payload pengujian bebas.
Dapat digunakan saat endpoint nonaktif, tanpa batas langganan peristiwa atau filter modul. Mapping saat ini tetap diterapkan. Respons menunggu pengiriman dan percobaan otomatis selesai.
Contoh penerima menolak format standar dengan HTTP 403:
{ "success": false, "delivered": 0, "delivery_id": 45, "status": "error", "delivery": { "id": 45, "endpoint_id": 12, "event_type": "webhook.test", "task_id": null, "status": "error", "attempts": 3, "response_status_code": 403, "response_body": "Forbidden", "error": "HTTP 403", "created_at": "2026-10-15T10:01:00Z", "updated_at": "2026-10-15T10:01:07Z", "delivered_at": null, "request_payload": { "schema_version": "1.0", "event": "webhook.test", "occurred_at": "2026-10-15T10:01:00Z", "source": "deskgram", "test": true, "endpoint": {"id": 12, "name": "CRM: рассылка"} }, "source_payload": { "schema_version": "1.0", "event": "webhook.test", "occurred_at": "2026-10-15T10:01:00Z", "source": "deskgram", "test": true, "endpoint": {"id": 12, "name": "CRM: рассылка"} } }}HTTP API lokal tetap 200. Angka 403 adalah status penerima di dalam delivery. Berhasil: success: true, delivered: 1, status: "success".
Jika catatan tidak dibuat, delivery_id dan delivery dapat null, success false. Endpoint hilang menghasilkan HTTP 404 lokal.
GET /api/webhooks/deliveries
Daftar pengiriman berdasarkan pembuatan, terbaru dahulu.
| Parameter query | Tipe | Bawaan | Arti |
|---|---|---|---|
endpoint_id | integer | Tidak ditentukan | ID endpoint |
event_type | string | Tidak ditentukan | Nama persis, misalnya message.failed |
status | string | Tidak ditentukan | pending, retrying, success, error |
limit | integer | 100 | 1–500 catatan |
Respons: {"deliveries": [...]}. Setiap objek tanpa requestpayload dan sourcepayload. Tidak ada offset, kursor, atau jumlah keseluruhan.
GET /api/webhooks/deliveries/{delivery_id}
Detail dengan requestpayload dan sourcepayload: {"delivery": {...}}. Tidak ditemukan: HTTP 404.
POST /api/webhooks/deliveries/{delivery_id}/retry
Mencoba ulang secara manual catatan berstatus error. Tidak membutuhkan badan. Membuat catatan baru dan menunggu percobaannya selesai. Diizinkan meskipun endpoint nonaktif.
Respons memuat success boolean, originaldeliveryid integer, status string, dan delivery baru lengkap. id serta X-Deskgram-Delivery-Id berbeda; catatan awal tetap. Kegagalan penerima tetap HTTP 200 lokal dengan success: false.
HTTP 400: sumber bukan error atau percobaan manualnya sedang berjalan dalam proses ini. HTTP 404: delivery atau endpoint tidak ditemukan.
GET /api/webhooks/events
Katalog enam peristiwa beserta label. Contoh mempertahankan label Rusia yang memang dikembalikan API; penerjemahan dokumen tidak mengubah nilai tersebut.
{ "events": [ {"event": "task.completed", "label": "Задача завершена"}, {"event": "task.failed", "label": "Задача завершилась ошибкой"}, {"event": "task.cancelled", "label": "Задача остановлена"}, {"event": "lead.reply_received", "label": "Получен ответ лида"}, {"event": "message.sent", "label": "Сообщение отправлено"}, {"event": "message.failed", "label": "Ошибка отправки сообщения"} ]}webhook.test dikirim lewat metode pengujian dan tidak ada dalam katalog langganan. "*" diterima di pengaturan tetapi juga tidak dicantumkan katalog.
Objek delivery
| Bidang | Tipe | Arti |
|---|---|---|
id | integer | ID dalam basis data lokal |
endpoint_id | integer | ID endpoint, termasuk yang kemudian dihapus |
event_type | string | Nama peristiwa terlepas dari mapping keluaran |
task_id | string atau null | ID tugas jika tersedia |
status | string | pending, retrying, success, error |
attempts | integer | Jumlah percobaan otomatis |
responsestatuscode | integer atau null | Status HTTP terakhir; bisa null pada gangguan jaringan |
response_body | string atau null | Respons terakhir dipotong; bisa null pada gangguan jaringan |
error | string atau null | Diagnostik, bukan bidang kesalahan bisnis CRM |
createdat, updatedat | string | Waktu UTC ISO 8601 berakhiran Z |
delivered_at | string atau null | Waktu pengiriman berhasil |
request_payload | object | JSON sesudah mapping; hanya detail/test/retry |
source_payload | object | Peristiwa asli; catatan lama mungkin {}; hanya detail/test/retry |
Transport biasa menyimpan respons sampai 2000 karakter; transport MCP terlindungi juga membatasi byte yang dibaca. Riwayat bukan jejak HTTP lengkap: header terkirim dan semua respons percobaan perantara tidak disimpan.
Peristiwa dan JSON keluar
Contoh menggunakan payload_template: "deskgram". Mapping mengubah struktur luar, tetapi X-Deskgram-Event tetap nama peristiwa.
Peristiwa akhir tugas
| Peristiwa | Arti |
|---|---|
task.completed | Eksekusi selesai, tidak menjamin setiap tindakan berhasil |
task.failed | Status akhir gagal |
task.cancelled | Tugas dihentikan/dibatalkan |
{ "schema_version": "1.0", "event": "task.completed", "occurred_at": "2026-10-15T10:05:00Z", "source": "deskgram", "task": { "task_id": "12345", "task_name": "Тестовая рассылка", "module_name": "spam_pm", "status": "completed", "created_at": "2026-10-15T10:04:00Z", "completed_at": "2026-10-15T10:05:00Z", "accounts_count": 1, "params": {}, "statistics": {}, "result": {} }}params, statistics, result bergantung pada modul; tidak ada skema penghitung universal. taskname, modulename, created_at bisa null. Failed/cancelled memakai keluarga struktur sama dengan peristiwa, status, hasil yang sesuai.
Peristiwa pesan langsung
Saat ini message.sent, message.failed, lead.replyreceived terhubung ke spampm. Filter modul lain tidak menciptakan sumber baru.
Contoh pesan terkirim:
{ "schema_version": "1.0", "event": "message.sent", "occurred_at": "2026-10-15T10:04:20Z", "source": "deskgram", "module": "spam_pm", "task": { "task_id": "12345", "campaign_id": "spam_pm:12345", "module_name": "spam_pm" }, "account": {"id": "987654321"}, "lead": { "telegram_user_id": "123456789", "username": "example_client", "raw_identifier": "@example_client" }, "message": { "message_id": 1001, "message_text": "Здравствуйте!", "raw_identifier": "@example_client", "text": "Здравствуйте!", "status": "sent" }}lead dan message bergantung data yang tersedia. Telepon, username, nama, ID, atau teks bisa tidak ada. Gunakan message.text untuk mapping teks. message_text adalah tambahan jalur tertentu, bukan bidang universal.
message.failed memuat error dan status yang tersedia di message; ID pesan terkirim mungkin tidak ada. Melewati penerima atau gagal mengenalinya tidak selalu menghasilkan peristiwa.
lead.replyreceived dapat memuat messageid, text, media_type, datetime, timestamp, status: "received". Hanya muncul jika penangan aktif benar-benar menerima balasan. Webhook tidak menyalakan pemantauan terus-menerus atau menjamin balasan setelah tugas selesai.
message.sent bukan bukti dibaca. Perlakukan ID sebagai nilai buram: ID tugas, akun, pengguna Telegram berupa string; message_id tertentu dapat berupa angka.
Peristiwa pengujian
Memuat schemaversion, event: "webhook.test", occurredat, source, test: true, endpoint: {id, name}. Struktur lengkap terdapat pada contoh metode test.
Tidak ada task, lead, account, atau message. Mapping hanya dari lead menghasilkan {}.
Pemetaan bidang
deskgram mengirim seluruh peristiwa asli dan mengabaikan payload_mapping. Pilih format lain untuk membatasi data.
Untuk shortresult, crmlead, custom, format eksplisit yang disarankan:
{ "fields": [ {"target": "event", "source": "event", "enabled": true}, {"target": "contact.telegram_id", "source": "lead.telegram_user_id", "enabled": true}, {"target": "contact.username", "source": "lead.username", "enabled": true}, {"target": "comment", "source": "message.text", "enabled": true}, {"target": "status", "source": ["message.status", "task.status"], "enabled": true} ]}Masukkan seluruh objek ke payload_mapping. target adalah jalur penerima; source adalah jalur dalam peristiwa asli, bukan konstanta atau ekspresi.
Hasil contoh message.sent:
{ "event": "message.sent", "contact": {"telegram_id": "123456789", "username": "example_client"}, "comment": "Здравствуйте!", "status": "sent"}Aturan:
- Titik pada target membuat objek bertingkat. Hindari jalur bertabrakan seperti contact dan contact.username sekaligus.
- source membaca kunci objek dengan titik; tidak mendukung indeks array atau templat
{{...}}. - Nilai tidak tersedia/null dihilangkan. Sumber tunggal mempertahankan 0, false, string kosong dengan tipe JSON asli.
- Daftar sumber memilih nilai pertama selain null, string kosong, daftar kosong, objek kosong. Bentuk
"message.status|task.status"juga didukung. - enabled: false meniadakan bidang; tidak ada enabled berarti aktif.
{"fields": []}atau semua dinonaktifkan menghasilkan{}, tanpa menggantinya dengan payload lengkap.- payloadmapping: {} memakai bidang bawaan pada shortresult/crm_lead; custom menghasilkan {}. fields eksplisit menetapkan kontrak pasti.
shortresult bawaan menggunakan event, occurredat, taskid, module, status, lead, message, error yang tersedia. crmlead bawaan menggunakan event, occurredat, taskid, accountid, telegramuserid, username, phone, firstname, lastname, rawidentifier, messageid, messagetext, messagestatus, messageerror.
Antarmuka dapat menyimpan daftar fields tersendiri yang bisa diedit untuk preset. Pengaturan tersimpan menentukan keluaran aktual, bukan hanya nama preset.
Header keluar
| Header | Nilai |
|---|---|
Content-Type | application/json |
User-Agent | Deskgram-Webhooks/1.0 |
X-Deskgram-Delivery-Id | ID catatan berupa string |
X-Deskgram-Event | Nama peristiwa |
x-secret | Rahasia bersama jika diatur |
X-Deskgram-Webhook-Secret | Rahasia yang sama |
X-Deskgram-Signature | Tanda tangan sha256= jika ada rahasia |
Rahasia dipakai untuk HMAC sekaligus dikirim melalui dua header. Gunakan HTTPS dan jangan mencatat nilainya dalam log publik.
headers tidak dapat mengganti Content-Type, User-Agent, Delivery-Id, Event serta tiga header rahasia saat dikonfigurasi, tanpa memandang kapitalisasi. Header lain, misalnya Authorization penerima, ditambahkan terpisah.
Verifikasi tanda tangan
Algoritme: HMAC-SHA256(secretutf8, rawrequest_body). Header berisi sha256= diikuti digest heksadesimal huruf kecil.
Yang ditandatangani adalah byte persis yang dikirim. JSON UTF-8, tanpa escape ASCII teks non-ASCII, kunci diurutkan, pemisah ringkas. Gunakan badan HTTP mentah, bukan JSON yang diparse lalu diserialkan ulang.
Contoh Python hanya memakai pustaka standar:
import hashlibimport hmacdef verify_deskgram_signature(raw_body: bytes, signature: str, secret: str) -> bool: if not secret or not signature: return False expected = "sha256=" + hmac.new( secret.encode("utf-8"), raw_body, hashlib.sha256 ).hexdigest() try: return hmac.compare_digest(expected, signature) except TypeError: return FalseBerikan byte mentah, X-Deskgram-Signature, dan rahasia tersimpan di penerima. Jangan menjalankan tindakan bisnis jika verifikasi gagal. Ambil rahasia dari konfigurasi terlindungi, bukan x-secret masuk.
Tanda tangan saja tidak mencegah pengulangan badan bertanda tangan. Penerima memerlukan pemeriksaan umur dan deduplikasi. Delivery-Id tidak masuk badan bertanda tangan. Rahasia dipangkas; gunakan ASCII tidak kosong tanpa spasi tepi, sampai 1000 karakter.
Percobaan ulang dan jaminan
- Hanya HTTP 200–299 berhasil; 3xx tidak diikuti. HTTP 200 dengan kesalahan bisnis JSON tetap keberhasilan transport.
- Maksimal tiga percobaan, jeda sekitar 2 dan 4 detik sebelum kedua/ketiga. Gangguan jaringan dan HTTP termasuk 4xx diulang. Retry-After tidak ditangani khusus.
- Percobaan otomatis mempertahankan badan dan Delivery-Id. Penerima harus menghindari tindakan ganda setelah berhasil.
- Retry manual memakai URL, rahasia, headers saat ini. Dengan sourcepayload, mapping saat ini diterapkan pada peristiwa asli; catatan lama tanpa sumber mengirim requestpayload tersimpan tanpa mapping kedua.
- Retry manual membuat Delivery-Id baru. Deduplikasi bisnis juga perlu identitas tugas/akun/pesan dan jenis peristiwa sesuai alur.
- Delivery-Id unik dalam satu basis data lokal, bukan semua instalasi. Bedakan pengirim jika ada beberapa.
- Tidak menjamin exactly-once, urutan antarperistiwa, atau pemulihan antrean otomatis setelah proses berhenti. Catatan pending/retrying terputus tidak berarti dilanjutkan saat mulai lagi.
- Menonaktifkan menghentikan pemilihan otomatis baru, bukan pengiriman berjalan. Test/retry eksplisit bisa mengirim ke endpoint nonaktif.
Alur penerima yang disarankan: verifikasi, simpan atau antrekan dengan andal, balas 2xx, lakukan pemrosesan lama secara terpisah.
Kesalahan API
| HTTP lokal | Kondisi |
|---|---|
| 200 | Operasi selesai; periksa success/delivery pada test/retry |
| 400 | Metode/format/peristiwa tidak didukung, URL tanpa http(s), retry tidak valid |
| 404 | Endpoint/delivery hilang atau endpoint asal dihapus |
| 422 | Validasi badan, tipe, atau rentang limit/timeout gagal |
Contoh; teks server sebenarnya bisa tetap Rusia:
{"detail": "Webhook endpoint не найден"}Pada validasi, detail bisa array diagnostik FastAPI, bukan string. Gangguan basis data/backend bisa menghasilkan kesalahan server; itu berbeda dari respons CRM luar.
Perbedaan MCP
MCP adalah antarmuka pengelolaan agen AI tersendiri, bukan nama lain REST API ini. Lihat koneksi MCP.
| Sifat | REST lokal | Alat MCP |
|---|---|---|
| Endpoint baru | enabled=true bawaan | Nonaktif |
| Pratinjau | Permintaan dijalankan | Pembuatan/perubahan default dry-run sesuai pengaturan MCP |
| Pembaruan | PUT penuh, pengecualian secret | Sebagian |
| URL | http(s); jangan publikasikan API lokal | Hanya HTTPS publik dengan perlindungan jaringan |
| Timeout | 3–60 detik | 3–30 detik |
| Pembacaan | URL, nilai headers, detail payload lengkap | Tanpa rahasia, nilai headers, badan lengkap |
Endpoint yang dibuat atau diambil alih lewat tindakan MCP nyata yang sesuai mempertahankan perlindungan untuk pengiriman berikutnya, termasuk dari antarmuka. PUT biasa tidak menghapusnya. Membaca, dry-run, menonaktifkan, menghapus tidak dengan sendirinya memasukkan endpoint lama ke kebijakan baru.
Sumber kontrak
Untuk pemeliharaan: model/rute web/routes/api/webhooks.py; peristiwa, tanda tangan, retry web/webhookdispatcher.py; data langsung functions/functions/spampm/crmintegration.py; transport terlindungi web/webhooknetwork.py; MCP web/mcp/webhooks.py. Jalur repositori ini untuk pengelola; konfigurasi tidak membutuhkan akses kode.