
# Webhook

Webhook memungkinkan <span data-t="appName">Your AI Connector</span> untuk secara otomatis memberi tahu alat bisnis Anda yang lain setiap kali terjadi sesuatu yang penting — kontak baru dibuat, janji temu dipesan, atau pesan diterima. Alih-alih memeriksa pembaruan secara manual, sistem Anda yang terhubung akan mendapatkan pemberitahuan instan saat sesuatu terjadi.


---

## Apa Itu Webhook?

Bayangkan webhook seperti pesan teks otomatis antara dua aplikasi. Saat sesuatu terjadi di <span data-t="appName">Your AI Connector</span> (seperti pendaftaran kontak baru), platform akan langsung mengirimkan pemberitahuan ke sistem lain pilihan Anda. Anda memberikan alamat web (disebut "URL webhook") tempat pemberitahuan ini harus dikirim — ini biasanya disediakan oleh CRM, platform otomatisasi, atau pengembang Anda.

> **Webhook hanya mengirim data KELUAR dari <span data-t="appName">Your AI Connector</span>.** Webhook adalah jalan satu arah *dari* <span data-t="appName">Your AI Connector</span> *ke* alat Anda yang lain. **Tidak ada URL webhook yang mengirim prospek, kontak, atau pesan KE DALAM platform.** Untuk memasukkan prospek baru — dari formulir situs web, CRM Anda, atau GoHighLevel — sistem Anda melakukan **panggilan API** sebagai gantinya. Lihat [Akses API](api-access.md) (operasi *Buat Kontak*) dan [Corong](funnels.md). Satu-satunya hal yang Anda perlukan untuk arah masuk adalah **kunci API** Anda, yang berada di bagiannya sendiri — lihat [Akses API](api-access.md#generating-your-api-key). Halaman **Webhook** yang dijelaskan di sini khusus untuk arah keluar.

::: note
**Catatan:** Menyiapkan webhook melibatkan beberapa konfigurasi teknis. Jika Anda tidak nyaman dengan hal ini, bagikan halaman ini kepada pengembang Anda atau gunakan platform otomatisasi seperti Zapier, Make, atau Pabbly, yang menyediakan URL webhook tanpa perlu pengkodean.
:::


Penggunaan umum meliputi:

- Menyinkronkan kontak baru ke CRM Anda.
- Memicu alur kerja di Zapier, Make, atau Pabbly saat tag diterapkan.
- Memberi tahu tim Anda di Slack saat manusia diberi peringatan.
- Memperbarui sistem kalender Anda saat janji temu dipesan.
- Mencatat ringkasan percakapan ke basis data Anda.

---

## Menyiapkan Webhook

1. Di bilah sisi kiri, klik **Pengaturan** (ikon roda gigi).
2. Di bilah sisi Pengaturan, di bawah grup **Integrasi**, klik **Webhook**.


Pada akun yang belum dikonfigurasi webhook-nya, halaman akan terlihat seperti ini:


3. Klik **New webhook**, di kanan atas. Formulir akan terbuka secara inline di halaman tersebut:


4. Isi:
   - **URL Endpoint** — alamat web tempat <span data-t="appName">Your AI Connector</span> akan mengirimkan pemberitahuan peristiwa. Anda mendapatkan ini dari sistem eksternal Anda (CRM, platform otomatisasi, atau server kustom).
   - **Nama** — label yang akan Anda kenali nanti (misalnya "Peringatan Slack" atau "Sinkronisasi CRM"). Hanya untuk referensi Anda.

> **URL webhook Anda harus berupa alamat `https://` yang dapat dijangkau publik.** Alamat `http://` biasa, `localhost` atau alamat jaringan pribadi, dan alamat internal platform akan ditolak saat Anda menyimpan. Untuk menguji dari mesin Anda sendiri, gunakan tunnel publik (webhook.site atau ngrok) alih-alih localhost.

5. Di bawah **Events**, klik peristiwa yang ingin Anda terima oleh webhook ini — ke-22 peristiwa tersebut tercantum dalam [The 22 Webhook Events](#the-22-webhook-events).
6. *(Opsional)* Aktifkan **Retry failed deliveries** jika Anda ingin <span data-t="appName">Your AI Connector</span> terus mencoba saat terjadi kegagalan sementara — lihat [Retrying Failed Deliveries](#retrying-failed-deliveries).
7. Klik **Create webhook**. Webhook akan muncul di daftar di bawah formulir, dan Anda dapat mengeklik **Test** pada barisnya kapan saja untuk mengirim payload contoh ke endpoint Anda.

> **Izin diperlukan.** Menambah, mengedit, atau menguji webhook memerlukan izin "edit" Integrasi (anggota tim dengan akses lihat-saja akan melihat pemberitahuan baca-saja alih-alih formulir).

> **Menandatangani webhook** mengharuskan webhook tersebut sudah disimpan terlebih dahulu — buka baris webhook yang ada untuk mengeditnya, dan panel **Rahasia penandatanganan** akan muncul di bagian bawah formulir edit. Draf baru yang belum disimpan belum memiliki opsi penandatanganan — lihat [Payload yang Ditandatangani](#signed-payloads-verifying-a-webhook-really-came-from-us) di bawah.

---

## Satu Webhook untuk Semua Akun Klien Anda (Agensi)

Jika Anda menjalankan agensi, Anda tidak perlu membuat ulang webhook yang sama di setiap akun klien. Pada akun agensi, formulir webhook memiliki tombol alih tambahan: **Juga aktifkan untuk semua akun klien**. Aktifkan tombol ini dan webhook ini juga akan menerima acara yang terjadi di setiap akun klien di bawah agensi Anda — satu endpoint, seluruh agensi.

Cara kerjanya:

- **Blok `user` memberi tahu Anda milik siapa acara tersebut.** Setiap notifikasi sudah membawa blok `user` yang mengidentifikasi akun tempat acara tersebut terjadi, sehingga otomatisasi Anda dapat melakukan perutean per klien.
- **Pengaturan webhook Anda sendiri berlaku di mana saja.** Acara yang Anda pilih, rahasia penandatanganan, dan pengaturan coba lagi juga digunakan untuk pengiriman akun klien.
- **Tidak ada pengiriman ganda.** Jika akun klien memiliki webhook sendiri yang mengarah ke URL yang sama, webhook tersebut yang akan digunakan untuk acara akun itu — acara yang sama tidak akan pernah tiba dua kali di satu endpoint.
- **Klien tidak melihatnya.** Webhook tersebut tidak muncul di halaman Webhook milik akun klien, dan klien tidak dapat mematikannya — webhook tersebut sepenuhnya di bawah kendali Anda.
- **Keandalan dilacak per akun klien.** Jika endpoint Anda terus gagal, webhook akan dimatikan secara otomatis untuk akun yang pengirimannya gagal (lihat [Keandalan Webhook](#webhook-reliability)), bukan untuk seluruh agensi sekaligus.

Tombol alih ini hanya muncul di akun agensi. Pengaturan melalui API juga didukung — lihat kolom `apply_to_sub_accounts` di [API Webhook](../api/webhooks.md#one-subscription-for-all-client-accounts-agencies).

---

## Acara Pemicu yang Tersedia

Anda dapat mengaktifkan atau menonaktifkan masing-masing dari 22 peristiwa webhook secara independen. Saat suatu peristiwa dipicu, <span data-t="appName">Your AI Connector</span> mengirimkan notifikasi ke URL webhook Anda dengan data yang relevan. Setiap peristiwa, artinya, dan kode `event` yang dimasukkannya ke dalam payload tercantum bersama dalam [The 22 Webhook Events](#the-22-webhook-events) di bagian bawah halaman ini.

> **Perlu diketahui:** **Task Created**, **Task Updated**, dan **Task Completed** dapat dipilih sepenuhnya dan disimpan dengan benar. **Daily Summary Created** juga merupakan tambahan baru. Lihat [Task Completed Webhook](#task-completed-webhook) di bawah untuk bentuk payload tersebut.

---

## Pemicu Webhook Berbasis Tag

`subscribed_to_tags` tidak membatasi peristiwa webhook ke tag tertentu. Ini hanya mempersempit tag mana yang menghasilkan notifikasi ringkasan percakapan. Untuk mendapatkan permintaan saat tag tertentu diterapkan, atur URL webhook pada tag tersebut di tab **Tags** pada agen (atau kampanye).

Formulir webhook itu sendiri tidak memiliki pemilih tag, baik saat membuat webhook baru maupun saat mengeditnya, sehingga `subscribed_to_tags` hanya dapat dibaca atau diubah melalui [Webhooks API](../api/webhooks.md), atau dengan meminta bantuan dukungan.

> **Perlu diketahui:** mengedit webhook yang sudah ada yang memiliki daftar `subscribed_to_tags` (mengganti nama, mengubah peristiwanya, mengaktifkan/menonaktifkan percobaan ulang) tidak lagi menghapus daftar tersebut — karena formulir tidak memiliki pemilih tag untuk dikirim kembali, menyimpan dari halaman ini sekarang membiarkan daftar yang ada tidak tersentuh. (Ini adalah bug nyata sebelum **21 Juli 2026**: menyimpan dari formulir webhook dulu menghapus daftar karena selalu mengirim daftar tag kosong. Jika webhook kehilangan daftar `subscribed_to_tags`-nya sebelum tanggal tersebut, webhook perlu dikonfigurasi ulang melalui API.)

### Hasilkan Ringkasan untuk Kontak yang Ditandai

Jika webhook memiliki daftar `subscribed_to_tags`, Anda dapat mengaktifkan **Generate Summary**. Saat diaktifkan, <span data-t="appName">Your AI Connector</span> secara otomatis membuat ringkasan percakapan untuk kontak tersebut saat salah satu tag tersebut diterapkan, dan menyertakannya dalam data webhook — konteks lengkap tanpa perlu permintaan terpisah.

---

## Menguji Webhook Anda

1. Buka **Pengaturan → Integrasi → Webhook**.
2. Pada baris webhook Anda, klik **Uji**.
3. Periksa sistem eksternal Anda untuk memastikan data pengujian telah diterima.
4. Tinjau format data untuk memastikan sistem Anda dapat mengurainya dengan benar.

Untuk pengujian menyeluruh dari awal hingga akhir, kirim pesan yang akan memicu salah satu peristiwa yang telah Anda konfigurasi (siaran, atau pesan masuk di saluran yang terhubung) dan verifikasi bahwa webhook aktif dengan data yang sebenarnya.

::: tip
**Tips:** Gunakan alat seperti [webhook.site](https://webhook.site) atau [RequestBin](https://requestbin.com) selama pengembangan untuk memeriksa data webhook mentah sebelum menghubungkannya ke sistem produksi Anda.
:::


### Apa yang Dianggap sebagai Pengiriman Berhasil

Baik Anda mengeklik **Test** atau peristiwa tersebut benar-benar dipicu, kami mengirimkan hal yang sama:

- Permintaan **POST** (bukan GET), dengan isi sebagai JSON dan `Content-Type: application/json`.
- Header yang tercantum di bawah [Signed Payloads](#signed-payloads-verifying-a-webhook-really-came-from-us). Header tanda tangan hanya disertakan setelah Anda menetapkan rahasia penandatanganan (signing secret).

Kami menganggap pengiriman berhasil jika:

- Endpoint Anda menjawab dengan **status 2xx apa pun** (200, 201, 204 — semuanya baik).
- Menjawab **dalam waktu 30 detik**.

Beberapa hal yang mengejutkan orang:

- **Isi respons diabaikan.** Anda tidak perlu mengembalikan JSON tertentu. Respons 200 kosong sudah cukup.
- **Pengalihan (redirect) dihitung sebagai kegagalan.** Kami tidak mengikuti pengalihan, jadi 301 atau 302 (termasuk pengalihan garis miring di akhir, atau http ke https) dicatat sebagai pengiriman yang gagal. Simpan URL akhir, bukan URL yang mengalihkan.
- **String kueri didukung sepenuhnya.** `https://your-app.com/hook?token=abc123` dikirim persis seperti yang Anda simpan, jadi menempatkan token di string kueri berfungsi sama baiknya dengan menempatkannya di jalur.
- **URL Anda harus `https://` dan dapat dijangkau secara publik.** Alamat yang termasuk dalam infrastruktur <span data-t="appName">Your AI Connector</span> sendiri akan ditolak, tetapi endpoint Anda sendiri di Google Cloud Functions, Cloud Run, App Engine, Firebase Hosting, atau tempat lain tidak masalah.
- **Firewall atau lapisan perlindungan bot di depan endpoint Anda dapat memblokir kami.** Kasus yang paling umum adalah Cloudflare: jika zona Anda mengaktifkan Bot Fight Mode atau tantangan terkelola, permintaan kami akan mendapatkan halaman tantangan "Just a moment..." dengan status 403 alih-alih mencapai server Anda — dan permintaan server-ke-server tidak akan pernah bisa melewati tantangan browser, jadi tombol **Test** dan peristiwa nyata akan gagal dengan cara yang sama. Tombol Test akan memberi tahu Anda saat hal ini terjadi ("Cloudflare is showing a bot challenge to our request"). Perbaiki di Cloudflare dengan aturan Keamanan / WAF yang melewati tantangan untuk jalur webhook Anda (atau untuk agen pengguna `Webhook-Delivery/1.0`), lalu klik **Test** lagi.
- **Jika firewall Anda memerlukan daftar izin IP sebagai gantinya** (misalnya paket gratis Cloudflare, di mana Bot Fight Mode biasa tidak dapat dilewati oleh aturan WAF, tetapi Aturan Akses IP yang diatur ke Izinkan berjalan sebelumnya), kami dapat membantu: setiap pengiriman, baik dari tombol **Test** atau peristiwa langsung, dikirim dari satu alamat IPv4 tetap (tanpa rentang, tanpa IPv6, tanpa rotasi). Hubungi dukungan dan kami akan memberikan alamat untuk dimasukkan ke daftar izin. Tetap gunakan [verifikasi tanda tangan](#signed-payloads-verifying-a-webhook-really-came-from-us) sebagai pemeriksaan kepercayaan Anda yang sebenarnya, karena verifikasi ini memvalidasi setiap payload terlepas dari mana asalnya.
- **Hasil Test memberi tahu Anda dengan tepat apa yang dijawab oleh endpoint Anda.** Tes yang gagal sekarang menunjukkan alasan sebenarnya (status HTTP yang dikembalikan endpoint Anda, waktu habis, atau bahwa kami tidak dapat menjangkau alamat tersebut sama sekali) alih-alih kesalahan umum, dan tes pada webhook yang disimpan dikirim dengan tanda tangan saat penandatanganan aktif, persis seperti peristiwa langsung.

### Menggunakan n8n, Make, atau Zapier ("Test URL" vs "Production URL")

Platform otomatisasi biasanya memberikan dua alamat webhook yang berbeda, dan hal ini sering membingungkan pengguna:

- **URL Uji** (di n8n berisi `/webhook-test/`). URL ini hanya menerima data saat Anda sedang aktif memantau kanvas dan baru saja mengeklik **Dengarkan peristiwa uji** (atau **Uji alur kerja**). URL ini menangkap satu peristiwa lalu berhenti mendengarkan — jadi mengeklik **Uji** di <span data-t="appName">Your AI Connector</span> beberapa kali berturut-turut hanya akan menangkap yang pertama, dan hanya jika jendela pendengaran aktif pada saat yang tepat itu. Untuk menguji: klik **Dengarkan peristiwa uji** di n8n terlebih dahulu, lalu kembali ke <span data-t="appName">Your AI Connector</span> dan klik **Uji** sekali.
- **URL Produksi** (di n8n berisi `/webhook/`, tanpa `-test`). Ini adalah URL yang harus ditempelkan ke <span data-t="appName">Your AI Connector</span> untuk peristiwa langsung. URL ini hanya berfungsi setelah alur kerja Anda diaktifkan (**Active**). Jika alur kerja tidak aktif, n8n akan menolak permintaan dengan kesalahan "404 / webhook not registered", meskipun <span data-t="appName">Your AI Connector</span> telah mengirimkan data dengan benar.

Singkatnya: uji dengan URL Uji saat mendengarkan, tetapi agar webhook terus berfungsi pada kontak nyata, simpan **URL Produksi** di <span data-t="appName">Your AI Connector</span> dan pastikan alur kerja dalam status **Active**.

---

## Format Data Webhook

Saat webhook dipicu, <span data-t="appName">Your AI Connector</span> mengirimkan data terstruktur (JSON) ke URL webhook Anda. Jika Anda menggunakan platform otomatisasi seperti Zapier atau Make, platform tersebut akan mengurai data ini untuk Anda secara otomatis. Jika Anda membangun integrasi kustom:

```json
{
  "event": "contactCreated",
  "contact": { "id": "<contact-id>", "first_name": "Jane", "...": "..." },
  "campaign": { "id": "<campaign-id>", "name": "AI Receptionist", "status": "Live" },
  "agent": { "id": "<agent-id>", "name": "Front Desk" },
  "user": { "id": "<account-id>", "email": "owner@example.com" }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | String peristiwa persis yang memicu notifikasi (contohnya, `contactCreated`, `booked`). Ini **bukan** label tampilan yang diperlihatkan dalam daftar peristiwa; setiap label dan kode yang cocok dengannya ada di [The 22 Webhook Events](#the-22-webhook-events). |
| `contact` | Kontak yang terkait dengan peristiwa tersebut, atau `null` untuk peristiwa yang tidak terikat pada kontak (seperti `creditsRecharged`). |
| `campaign` | Kampanye tempat kontak tersebut berada, atau `null` jika tidak ada. |
| `agent` | Agen yang menangani percakapan, atau `null` jika tidak ada. |
| `user` | Informasi identitas dasar untuk akun yang memiliki data tersebut. |

> **`campaign` atau `agent` — biasanya salah satu, bukan keduanya.** Jika akun Anda menggunakan agen, kontak Anda berada di bawah agen, bukan kampanye, sehingga `campaign` muncul sebagai `null` dan `agent` memberi tahu Anda siapa yang menanganinya. Akun berbasis kampanye yang lebih lama melihat kebalikannya. Baca bagian mana pun yang terisi; jangan berasumsi `campaign` selalu ada.

> **Blok `agent` tiba pada 15 Agustus 2026.** Blok ini bersanding dengan `campaign` pada peristiwa yang terkait dengan percakapan — obrolan yang selesai, jangan ganggu, lanjutkan, batal arsip, jeda AI, pesan baru, ringkasan percakapan, dan webhook yang dapat Anda atur pada tag — serta membawa `id` dan `name` agen penangan, atau `null` jika tidak ada agen yang terlibat. Ini murni bersifat tambahan: setiap bidang yang sudah Anda terima tidak berubah, sehingga penerima yang Anda buat sebelum tanggal tersebut tetap berfungsi tanpa perlu pembaruan apa pun.

Beberapa peristiwa menambahkan blok tingkat atas tambahan mereka sendiri. Misalnya, **Appointment Booked** menambahkan blok `appointment` (lihat [Webhook Appointment Booked](#appointment-booked-webhook)), **New Message** menambahkan blok `message` lengkap dengan teksnya (lihat [Webhook New Message](#new-message-webhook)), dan **Deliveries** serta **Reads** menambahkan blok `message` singkat yang hanya berisi ID dan status pesan (lihat [Webhook Deliveries and Reads](#deliveries-and-reads-webhook)).

> **Deliveries dan Reads memberi tahu Anda pesan mana, tetapi bukan apa isinya.** Keduanya membawa blok `message` yang berisi `id` dan `status` pesan tersebut — dan `id` tersebut sama dengan `messageId` yang dikembalikan oleh [endpoint kirim pesan](../api/messages.md#send-a-message), sehingga Anda dapat mencocokkan tanda terima pengiriman atau pembacaan dengan pesan persis yang Anda kirim — tetapi tidak ada isi pesan. **Replies** tidak membawa blok `message` sama sekali. Jika Anda memerlukan kata-kata yang dikirim atau diterima, berlanggananlah ke **New Message** bersamaan dengan peristiwa tersebut.

> **Dua hal yang perlu diketahui sebelum Anda menulis penerima.** Tidak ada bidang `timestamp`, dan tidak ada pembungkus `data`. Setiap blok berada di tingkat atas objek JSON, seperti yang ditunjukkan di atas.

### The 22 Webhook Events

22 peristiwa webhook, dengan label tampilan yang Anda centang di aplikasi dan kode `event` yang dikirim dalam payload. Kode `event` adalah string pendek yang **tidak** cocok dengan label tampilan, jadi sesuaikan penerima Anda berdasarkan kodenya, bukan labelnya:

| Label tampilan (di aplikasi) | Kode `event` dalam payload | Artinya |
|---|---|---|
| Contact Created | `contactCreated` | Kontak baru ditambahkan ke akun Anda (secara manual, melalui impor, atau melalui API). |
| Contact Paused | `contact_paused` | Percakapan kontak dijeda (bot berhenti merespons). |
| Contact Resumed | `contact_resumed` | Percakapan kontak yang dijeda dilanjutkan. |
| Contact Do Not Disturb | `contact_do_not_disturb_changed` | Pengaturan Jangan Ganggu (Do Not Disturb) kontak diaktifkan. |
| Contact Unarchived | `contact_unarchived` | Kontak yang diarsipkan mengirim pesan baru, membawanya kembali ke kotak masuk aktif Anda. |
| New Message | `new_message` | Pesan apa pun ditambahkan ke percakapan di saluran mana pun — baik pesan yang dikirim kontak kepada Anda maupun pesan yang dikirim AI atau tim Anda kepada mereka. Ini adalah satu-satunya peristiwa yang membawa teks pesan sebenarnya (lihat [Webhook New Message](#new-message-webhook)). |
| Replies | `replied` | Kontak membalas pesan. |
| Reads | `read` | Kontak membaca pesan (pada saluran yang mendukung tanda terima telah dibaca). Membawa ID pesan yang dibaca — lihat [Webhook Deliveries and Reads](#deliveries-and-reads-webhook). |
| Deliveries | `delivered` atau `undelivered` | Pesan berhasil dikirim ke kontak (`undelivered` saat pengiriman gagal). Membawa ID pesan — lihat [Webhook Deliveries and Reads](#deliveries-and-reads-webhook). |
| Human Alerted | `humanAlerted` | Bot AI menentukan bahwa ia tidak dapat menangani percakapan dan menandainya untuk perhatian manusia. |
| Chat Concluded | `chat_concluded` | Bot AI memutuskan percakapan telah mencapai akhirnya (pemesanan dibuat, prospek didiskualifikasi, dll.). |
| Appointment Booked | `booked` | Kontak memesan janji temu melalui sistem pemesanan. |
| Credits Spent | `creditsSpent` | Kredit dipotong dari akun Anda. |
| Credits Recharged | `creditsRecharged` | Kredit ditambahkan ke akun Anda melalui isi ulang otomatis atau pembelian manual. |
| Low Credit Balance | `lowCreditBalance` pada pengiriman **Test**, `Low Credit Balance` pada pengiriman nyata | Peringatan dini bahwa saldo kredit Anda telah turun di bawah ambang batas peringatan (100 kredit kecuali Anda menetapkan sendiri). Ditujukan untuk agensi, yang semua sub-akunnya membelanjakan dari satu kumpulan. Ini membawa `balance`, `threshold`, dan `account_email` alih-alih blok kontak, dikirim paling banyak sekali setiap 24 jam selama saldo tetap rendah, dan diaktifkan kembali segera setelah saldo kembali di atas ambang batas. |
| Task Created | `taskCreated` | Tugas dibuat. |
| Task Updated | `taskUpdated` | Tugas berubah tanpa berpindah ke tahap penyelesaian. |
| Task Completed | `taskCompleted` | Tugas berpindah ke tahap yang dikonfigurasi sebagai tahap penyelesaian. |
| Daily Summary Created | `dailySummaryCreated` | Laporan ringkasan harian Anda dibuat. |
| Channel Connected | `channelConnected` | **Belum dikirim — dapat dipilih, tetapi tidak ada yang memancarkannya hari ini. Jangan membangun aplikasi berdasarkan ini.** Ditujukan untuk saat saluran pesan selesai terhubung. |
| Broadcast Started | `broadcastStarted` | Siaran mulai dikirim (statusnya berubah menjadi Sending). Terpicu sekali per mulai, termasuk saat siaran yang dijeda dilanjutkan. Membawa blok `broadcast` alih-alih blok kontak: id, nama, saluran, status, status sebelumnya, daftar yang ditargetkan (`list_id`, `list_name`, `is_smart_list`), `scheduled_at`, `total_contacts`. |
| Broadcast Completed | `broadcastCompleted` | Siaran selesai (statusnya berubah menjadi Sent atau Failed). Blok `broadcast` yang sama ditambah `completed_at` dan, jika tersedia, `completion_summary` (`total_sent`, `permanently_failed`, `unique_replied`, `failure_rate`, `had_errors`). Gunakan keduanya untuk menghubungkan Daftar Siaran Cerdas ke alat eksternal. |

Dua kode lagi tidak pernah muncul dalam daftar itu karena Anda tidak berlangganan: `contact_tags_updated`, dikirim oleh URL webhook yang diatur pada tag individu, dan `summary_generated`, dikirim saat ringkasan obrolan ditulis untuk tag dalam daftar `subscribed_to_tags` webhook.

> **Saluran Terhubung belum dikirim.** Ini muncul di daftar acara, tetapi tidak ada yang memicunya saat ini. Jangan membangun integrasi berdasarkan ini.

Notifikasi berbasis tag dan tugas menggunakan bentuknya sendiri yang terpisah. Lihat [Contact Tags Updated](#contact-tags-updated-webhook) dan [Task Completed](#task-completed-webhook).

---

## Webhook Kontak Dibuat

Dikirim saat peristiwa **Kontak Dibuat** aktif (kontak baru ditambahkan secara manual, melalui impor, atau melalui API).

### Nama peristiwa

`contactCreated`

### Format payload

```json
{
  "event": "contactCreated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `contactCreated` untuk kejadian ini. |
| `contact.id` | ID unik dari kontak baru. |
| `contact.email` / `contact.phone_number` | Email dan telepon kontak, jika diketahui (keduanya bisa kosong tergantung pada salurannya). |
| `contact.first_name` / `contact.last_name` | Nama kontak, jika diketahui. |
| `contact.human_alerted` / `contact.human_alert_reason` | Apakah kontak ditandai untuk perhatian manusia, dan alasannya. |
| `contact.is_bot_active` | Apakah bot AI saat ini aktif pada kontak ini. |
| `contact.ad_referral` | Atribusi iklan Meta Click-to-WhatsApp, atau `null` — lihat [Atribusi Iklan Click-to-WhatsApp](click-to-whatsapp-attribution.md). |
| `campaign` | Kampanye tempat kontak dibuat, atau `null`. |
| `agent` | Agen yang ditugaskan ke kontak, atau `null`. |
| `user` | Informasi identitas dasar untuk akun yang memiliki kontak tersebut. |

> **Sampel "Uji" dan peristiwa nyata terlihat sedikit berbeda.** Tombol uji mengirimkan data placeholder (John Doe, kampanye sampel). Peristiwa Kontak Dibuat yang nyata membawa detail kontak yang sebenarnya, dan beberapa bidang mungkin kosong tergantung pada saluran.

---

## Webhook Pesan Baru

Webhook ini dipicu setiap kali pesan ditambahkan ke percakapan, di saluran mana pun. Ini mencakup kedua arah: pesan yang dikirim kontak kepada Anda, dan pesan yang dikirim AI, tim Anda, atau kampanye kepada mereka. Ini adalah satu-satunya webhook yang menyertakan teks pesan, jadi ini adalah webhook yang digunakan saat Anda ingin mencerminkan percakapan ke sistem eksternal.

### Nama peristiwa

`new_message`

### Format payload

```json
{
  "event": "new_message",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "body": "Hi, are you open on Saturday?",
    "direction": "inbound",
    "status": "received",
    "created_at": "2026-07-30T17:27:06.000Z",
    "channel": "whatsapp_web"
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `new_message` untuk peristiwa ini. Perhatikan bahwa ini adalah string persis yang dikirim — ini bukan label tampilan "New Message". |
| `contact` | Kontak yang percakapannya menjadi milik pesan tersebut. Bentuknya sama seperti di [Contact Created](#contact-created-webhook). |
| `agent` | Agen yang menangani percakapan (`id` dan `name`), atau `null` jika tidak ada agen yang terlibat. |
| `user` | Informasi identitas dasar untuk akun yang memiliki percakapan tersebut. |
| `message.id` | ID unik pesan tersebut. |
| `message.body` | Teks pesan. Kosong untuk pesan yang hanya membawa lampiran (gambar, catatan suara, dokumen). |
| `message.direction` | `inbound` untuk pesan dari kontak, `outbound` untuk pesan yang dikirim oleh AI Anda atau oleh tim Anda dari kotak masuk, dan `outbound-api` untuk pesan yang dikirim oleh kampanye, siaran, pengiriman templat, atau API. |
| `message.status` | Di mana pesan berada dalam siklus hidupnya: `received` untuk masuk, dan `queued` / `sent` / `delivered` / `read` / `failed` / `undelivered` untuk keluar. Ini adalah status pada saat pesan dibuat, jadi pesan keluar biasanya tiba di sini sebagai `queued` atau `sent` dan mencapai `delivered` setelahnya — gunakan peristiwa **Deliveries** dan **Reads** jika Anda memerlukan transisi nanti. Keduanya membawa `message.id` yang sama dengan blok ini, sehingga Anda dapat mencocokkan transisi ke pesan ini (lihat [Webhook Deliveries and Reads](#deliveries-and-reads-webhook)). |
| `message.created_at` | Kapan pesan dibuat, dalam UTC (ISO 8601). |
| `message.channel` | Saluran yang dilalui pesan, misalnya `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `messenger`, `telegram`, `email`, atau `custom`. |

> **Masih belum ada blok `campaign` dalam payload ini.** Pesan Baru mengirimkan `contact`, `agent`, `user`, dan `message`. Blok `agent` ditambahkan pada **15 Agustus 2026** dan memberi tahu Anda agen mana yang menangani percakapan; jika Anda juga memerlukan konteks kampanye, cari kontak tersebut melalui API menggunakan `contact.id`.

> **Catatan AI internal tidak memicu webhook ini.** Selain pesan nyata, platform menyimpan baris pembukuan sendiri dalam percakapan (panggilan alat AI dan catatan giliran internal). Hal tersebut tidak pernah dikirim — Anda hanya menerima pesan yang benar-benar dikirim atau diterima.

---

## Webhook Deliveries and Reads

Kedua peristiwa ini melaporkan apa yang terjadi pada pesan setelah meninggalkan <span data-t="appName">Your AI Connector</span>: **Deliveries** terpicu saat pesan mencapai kontak (atau gagal mencapainya), dan **Reads** terpicu saat kontak membukanya, pada saluran yang mendukung tanda terima telah dibaca.

Keduanya membawa blok `message` dengan ID pesan yang dimaksud oleh peristiwa tersebut, sehingga Anda dapat mencocokkan pembaruan dengan pesan persis yang Anda kirim.

### Nama peristiwa

`delivered` dan `undelivered` untuk **Deliveries**, `read` untuk **Reads**.

### Format payload

```json
{
  "event": "delivered",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "status": "delivered"
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | `delivered` atau `undelivered` untuk **Deliveries**, `read` untuk **Reads**. |
| `contact` | Kontak yang dikirimi pesan. |
| `campaign` | Kampanye tempat kontak berada, atau `null`. |
| `agent` | Agen yang menangani percakapan, atau `null`. |
| `user` | Informasi identitas dasar untuk akun yang memiliki data tersebut. |
| `message.id` | ID pesan yang dimaksud oleh pembaruan ini. Ini adalah nilai yang sama yang dikembalikan oleh [endpoint kirim pesan](../api/messages.md#send-a-message) sebagai `messageId`, dan `message.id` yang sama yang dibawa oleh notifikasi [New Message](#new-message-webhook). |
| `message.status` | Status baru, selalu string yang sama dengan `event` (`delivered`, `undelivered`, atau `read`). |

> **Cara mencocokkan pembaruan dengan pesan yang Anda kirim.** Simpan `messageId` yang Anda dapatkan saat mengirim pesan melalui API. Saat notifikasi **Deliveries** atau **Reads** tiba, cari ID yang disimpan tersebut terhadap `message.id` di payload — itulah tanda terima pengiriman atau pembacaan Anda untuk pesan persis tersebut.

> **Tidak ada teks pesan di sini.** Blok `message` hanya membawa ID dan status. Berlanggananlah ke [New Message](#new-message-webhook) jika Anda juga memerlukan isi pesannya.

> **Blok `message` hanya ada jika kami mengetahui pesan mana itu.** Pada pembaruan langka yang tidak dapat kami kaitkan kembali ke pesan yang disimpan, blok tersebut ditinggalkan sepenuhnya daripada dikirim kosong — jadi periksa apakah `message` ada sebelum membaca `message.id`.

> **Satu notifikasi per perubahan status.** Satu pesan keluar biasanya menghasilkan notifikasi `delivered` dan kemudian, pada saluran dengan tanda terima telah dibaca, notifikasi `read`. Pengiriman yang gagal menghasilkan `undelivered` sebagai gantinya.

---

## Webhook Appointment Booked

Aktif saat kontak memesan janji temu. Peristiwa ini aktif dengan cara yang sama baik saat AI memesannya selama percakapan, Anda memesannya secara manual, atau melalui API.

### Nama peristiwa

`booked`

### Format payload

```json
{
  "event": "booked",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith"
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com"
  },
  "appointment": {
    "appointment_id": "<appointment-id>",
    "start_time": "2026-07-20T15:00:00.000Z",
    "end_time": "2026-07-20T15:30:00.000Z",
    "status": "confirmed",
    "room_name": "Room 1",
    "description": "Discovery call",
    "summary": "30 min intro",
    "google_calendar_event_id": null,
    "event": {
      "id": "<service-id>",
      "event_name": "Intro Call",
      "slot_duration": 30,
      "location": "Zoom",
      "meeting_link": "https://...",
      "event_type": "online"
    }
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `booked` untuk peristiwa ini. |
| `contact` | Orang yang memesan. `email` dan `phone_number` mungkin kosong tergantung pada salurannya. |
| `appointment.appointment_id` | ID unik pemesanan. |
| `appointment.start_time` / `end_time` | Awal dan akhir slot yang dipesan, dalam UTC (ISO 8601). |
| `appointment.status` | Status pemesanan saat ini. |
| `appointment.room_name` | Ruangan tempat pemesanan dilakukan, jika digunakan. |
| `appointment.description` / `summary` | Detail teks bebas yang ditangkap bersama pemesanan. |
| `appointment.google_calendar_event_id` | ID Google Kalender untuk acara yang disinkronkan. Seringkali `null` dalam webhook Appointment Booked, karena acara kalender dibuat pada saat yang sama notifikasi dikirim — ambil kembali janji temu berdasarkan `appointment_id`-nya beberapa saat kemudian jika Anda membutuhkannya, dan harapkan `null` permanen pada akun tanpa Google Kalender yang terhubung. |
| `appointment.event` | Layanan yang dipesan: nama, durasi slot, lokasi, tautan rapat, jenis. |

> **`google_calendar_event_id` sering kali `null` dalam webhook ini, dan itu normal.** Peristiwa Google Calendar dibuat pada saat yang sama dengan notifikasi ini keluar, jadi ID biasanya belum siap. Ambil kembali janji temu berdasarkan `appointment_id`-nya beberapa saat kemudian jika Anda membutuhkannya. ID tersebut akan tetap `null` secara permanen jika akun tidak memiliki Google Calendar yang terhubung, jadi jangan menunggu selamanya.

> **Tombol "Uji" tidak menyertakan blok `appointment`.** Gunakan tombol tersebut untuk mengonfirmasi bahwa endpoint Anda merespons, lalu buat satu pemesanan nyata untuk melihat payload lengkapnya.

> **Dua kasus di mana webhook ini tidak aktif:** janji temu yang diimpor dari kalender eksternal, dan pemesanan yang masuk melalui integrasi Formitable.

---

## Webhook Pembaruan Tag Kontak

Terpicu saat sebuah tag **diterapkan** ke kontak, dan tag tersebut memiliki URL webhook yang dikonfigurasi pada agen atau kampanye tempat kontak tersebut berada.

### Nama peristiwa

`contact_tags_updated`

### Kapan webhook ini dipicu

- Tag diterapkan ke kontak yang memiliki agen yang ditugaskan, kampanye yang ditugaskan, atau keduanya.
- Setidaknya salah satu tag yang diterapkan memiliki URL webhook yang diatur di tab Tag pada agen atau kampanye tersebut.

Jika kontak memiliki keduanya dan tag kampanye membawa URL webhook, tag tersebut yang digunakan; jika tidak, tag agen yang akan digunakan.

Jika beberapa tag dengan URL webhook yang berbeda diterapkan dalam pembaruan yang sama, satu permintaan akan dikirim per URL, masing-masing hanya berisi tag yang dipetakan ke URL tersebut.

**Menghapus tag tidak akan pernah mengirimkan permintaan.** Kebanyakan orang mengarahkan URL ini ke suatu tindakan — mengumpulkan deposit, memesan slot, memberi tahu perwakilan — sehingga tag yang dihapus dari kontak tidak lagi digunakan untuk menjalankan ulang tindakan tersebut. Penghapusan masih muncul di `removed_tags` jika terjadi dalam pembaruan yang sama dengan penerapan yang menuju ke URL yang sama, sehingga otomatisasi yang membaca kedua array tetap mendapatkan gambaran lengkap; yang tidak akan pernah dilihatnya adalah permintaan yang disebabkan oleh penghapusan saja. (Diubah pada **12 Agustus 2026**. Sebelum tanggal tersebut, penghapusan juga mengirimkan permintaan.)

### Format payload

```json
{
  "event": "contact_tags_updated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "is_bot_active": true,
    "ad_referral": {
      "ctwa_clid": "ARAbc123...",
      "source_id": "120210000000000",
      "source_type": "ad",
      "source_url": "https://fb.me/xxxx",
      "headline": "Get 20% off today",
      "body": "Message us now to claim your discount",
      "channel": "whatsapp"
    }
  },
  "added_tags": ["qualified-lead"],
  "removed_tags": ["new-lead"],
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `contact_tags_updated` untuk webhook ini. |
| `contact.id` | ID unik kontak yang tag-nya berubah. |
| `contact.email` / `contact.phone_number` | Email/telepon kontak, jika diketahui. |
| `contact.first_name` / `contact.last_name` | Nama kontak. |
| `contact.human_alerted` | Apakah kontak saat ini ditandai untuk perhatian manusia. |
| `contact.is_bot_active` | Apakah bot AI saat ini aktif pada percakapan kontak ini. |
| `contact.ad_referral` | Hanya muncul saat kontak pertama kali menghubungi Anda melalui iklan atau postingan Meta Click-to-WhatsApp (CTWA). `null` jika tidak. |
| `added_tags` | Larik nama tag yang diterapkan dalam pembaruan ini. Tidak pernah kosong — penerapan adalah hal yang memicu permintaan. |
| `removed_tags` | Larik nama tag yang dihapus dalam pembaruan yang sama, jika ada. Penghapusan saja tidak mengirimkan apa pun. |
| `agent` | Agen yang menangani percakapan kontak (`id` dan `name`), atau `null` jika tidak ada agen yang terlibat. Ditambahkan **15 Agustus 2026**. |
| `user` | Informasi identitas dasar untuk akun yang memiliki kontak tersebut. |

### Menguji webhook tag

Di samping kolom URL webhook pada tab Tag terdapat tombol **Uji**. Tombol ini akan segera mengirimkan payload sampel ke URL tersebut, sehingga Anda dapat memastikan otomatisasi Anda menerimanya sebelum menunggu percakapan yang sebenarnya.

Pengujian mengirimkan bentuk `contact_tags_updated` yang sama seperti yang ditunjukkan di atas, menggunakan kontak placeholder, dengan tag yang sedang Anda uji di `added_tags` dan `removed_tags` kosong. Apa yang dilihat otomatisasi Anda dalam pengujian adalah apa yang akan dilihatnya dalam produksi.

Dua hal yang perlu diketahui:

- **Simpan tag terlebih dahulu.** Tes mencari tag berdasarkan nama yang disimpan, jadi tag baru atau perubahan nama yang belum disimpan belum dapat diuji. Tombol tetap berwarna abu-abu sampai nama di layar cocok dengan yang disimpan.
- **Tes yang gagal tidak dihitung terhadap webhook Anda.** Tes tidak pernah berkontribusi pada penghentian otomatis setelah kegagalan berulang yang dijelaskan dalam [Webhook Reliability](#webhook-reliability).

Jika pengujian gagal, pesan akan memberi tahu Anda apa yang dijawab oleh endpoint Anda (misalnya `404` atau `500`), yang biasanya cukup untuk menemukan URL yang salah atau alur kerja yang belum diaktifkan.

---

## Webhook Tugas Selesai

> **Hanya untuk referensi.** Webhook tugas (sebagai data) didokumentasikan di sini untuk pengembang; peristiwa **Task Created**, **Task Updated**, dan **Task Completed** dapat dipilih dalam daftar peristiwa standar pada formulir webhook seperti peristiwa lainnya — lihat [Available Trigger Events](#available-trigger-events) dan [The 22 Webhook Events](#the-22-webhook-events).

Payload ini dikirim saat tugas beralih ke tahap yang ditandai sebagai tahap penyelesaian. Tugas yang berpindah antar tahap non-penyelesaian akan mengirimkan bentuk `taskUpdated` sebagai gantinya.

### Nama peristiwa

`taskCompleted`

### Kapan webhook ini dipicu

- Tugas diperbarui.
- Nilai `stage`-nya berubah dibandingkan dengan nilai sebelumnya.
- Tahap baru dikonfigurasi sebagai tahap penyelesaian pada pengaturan tahap tugas akun.

### Format payload

```json
{
  "event": "taskCompleted",
  "contact": {
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<task-id>",
    "title": "Follow up with Jane",
    "description": "Confirm pricing and send proposal",
    "type": "follow_up",
    "priority": "high",
    "stage": "<stage-id>",
    "due_date": "2026-01-20T15:00:00Z",
    "source": "ai",
    "source_detail": "<source-detail>",
    "campaign_id": "<campaign-id>",
    "linked_human_alert": "<human-alert-id>",
    "tags": ["qualified-lead"],
    "notes": "Customer requested a callback"
  }
}
```

| Bidang | Deskripsi |
|---|---|
| `event` | Selalu `taskCompleted` untuk webhook ini. Bentuk payload yang sama dikirim sebagai `taskUpdated` saat tugas berubah tanpa memasuki tahap penyelesaian. |
| `contact` | Kontak yang ditautkan ke tugas, jika ada. `null` jika tidak ditautkan. |
| `contact.human_alert_reason` | Alasan kontak ditandai untuk perhatian manusia, jika berlaku. |
| `user` | Informasi identitas dasar untuk akun yang memiliki tugas tersebut. |
| `message.id` | ID unik tugas. |
| `message.title` / `description` | Judul dan deskripsi tugas. |
| `message.type` | Jenis tugas (misalnya, `follow_up`, `call`, `custom`). |
| `message.priority` | Prioritas tugas (`low`, `medium`, `high`). |
| `message.stage` | ID tahap tempat tugas berada sekarang. |
| `message.due_date` | Tanggal jatuh tempo tugas, jika diatur. |
| `message.source` | Apa yang membuat tugas tersebut (`ai`, `manual`, `api`). |
| `message.source_detail` | Detail tambahan tentang sumbernya. |
| `message.campaign_id` | ID kampanye yang ditautkan, atau `null`. |
| `message.linked_human_alert` | ID peringatan manusia yang ditautkan, jika ada. |
| `message.tags` | Tag yang diterapkan pada tugas. |
| `message.notes` | Catatan bentuk bebas pada tugas. |

---

## Mematikan (atau Menghapus) Webhook

Setiap webhook memiliki tombol on/off, tepat di barisnya. Mematikan (**off**) webhook akan menghentikan penerimaan peristiwa, tetapi tetap menyimpan semua konfigurasi Anda — URL, peristiwa, dan rahasia penandatanganan apa pun. Nyalakan kembali dan webhook akan berlanjut dari titik terakhirnya; tidak ada peristiwa yang terjadi selama webhook dimatikan yang akan dikirimkan setelahnya.

Gunakan fitur ini saat Anda ingin menghentikan pengiriman untuk sementara: endpoint Anda sedang dibangun ulang, Anda sedang men-debug integrasi yang terlalu bising, atau Anda sedang menjeda otomatisasi.

**Menghapus** webhook (ikon tempat sampah di barisnya) akan menghilangkannya secara permanen, termasuk rahasia penandatanganannya. Jika Anda hanya ingin menghentikan pengiriman, matikan saja webhook tersebut — hapus hanya digunakan jika Anda sudah benar-benar selesai dengan endpoint tersebut.

> **Ini tidak sama dengan webhook yang dimatikan secara otomatis.** Jika kami menonaktifkan webhook Anda setelah kegagalan berulang (lihat [Keandalan Webhook](#webhook-reliability)), tombol di atas tidak akan mengaktifkannya kembali. Setelah endpoint Anda diperbaiki, edit webhook tersebut dan simpan dengan URL yang diubah (perubahan URL apa pun akan mengaktifkannya kembali), atau panggil [endpoint aktifkan kembali](../api/webhooks.md) melalui API — atau hubungi dukungan dan kami akan mengaktifkannya kembali untuk Anda.

---

## Payload Bertanda Tangan (Memverifikasi Bahwa Webhook Benar-benar Berasal dari Kami)

Siapa pun yang mengetahui URL webhook Anda dapat mengirimkan permintaan palsu palsu ke URL tersebut. Jika Anda menindaklanjuti webhook secara otomatis — memperbarui penagihan, membuat catatan CRM — mengaktifkan **penandatanganan** memungkinkan Anda memverifikasi bahwa setiap permintaan benar-benar berasal dari kami.

Penandatanganan bersifat **opsional dan dinonaktifkan secara default**, dan Anda dapat mengaktifkannya per webhook, dari tampilan edit webhook tersebut (buka baris webhook yang tersimpan).

### Mengaktifkan penandatanganan

1. Buka webhook (Pengaturan → Integrasi → Webhook → klik baris webhook Anda).
2. Di bagian **Signing secret**, klik **Generate**.
3. Salin secret tersebut (diawali dengan `whsec_`) dan simpan di sistem penerima Anda. Perlakukan secret ini seperti kata sandi.

Anda dapat kembali dan menampilkan, menyalin, merotasi, atau menonaktifkan secret kapan saja dari panel yang sama ini.

### Apa yang kami kirimkan

Setelah penandatanganan aktif, setiap pengiriman untuk webhook tersebut membawa dua header HTTP tambahan ini:

| Header | Arti |
|---|---|
| `X-Webhook-Signature` | Tanda tangan, dalam bentuk `v1=<hex>`. |
| `X-Webhook-Timestamp` | Kapan kami mengirimnya, sebagai stempel waktu Unix dalam detik. |

Ketiga header ini ada pada **setiap** pengiriman, baik ditandatangani maupun tidak:

| Header | Arti |
|---|---|
| `X-Webhook-Delivery` | ID unik untuk acara ini. Tetap sama di seluruh percobaan ulang, jadi ini yang Anda gunakan untuk deduplikasi. |
| `X-Webhook-Attempt` | Percobaan keberapa ini (`1` adalah percobaan pertama). |
| `X-Webhook-Event` | Nama acara, sehingga Anda dapat merutekan tanpa membaca isi pesan. |

### Cara memverifikasi

Tanda tangan adalah HMAC-SHA256 dari string `<timestamp>.<raw request body>`, menggunakan secret penandatanganan Anda sebagai kuncinya.

**Verifikasi terhadap badan permintaan mentah — byte yang tepat yang Anda terima.** Jika framework Anda mengurai JSON dan membuat serialisasi ulang sebelum memeriksa, byte tersebut dapat berubah dan tanda tangan tidak akan cocok.

Contoh Node.js:

```js
const crypto = require("crypto");

function verify(rawBody, headers, secret) {
  const timestamp = headers["x-webhook-timestamp"];
  const signature = headers["x-webhook-signature"]; // "v1=<hex>"

  // Reject anything older than 5 minutes so a captured request can't be replayed later.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");

  return crypto.timingSafeEqual(Buffer.from(signature.replace("v1=", "")), Buffer.from(expected));
}
```

Contoh Python:

```python
import hashlib, hmac, time

def verify(raw_body: bytes, headers, secret: str) -> bool:
    timestamp = headers["X-Webhook-Timestamp"]
    signature = headers["X-Webhook-Signature"].replace("v1=", "")

    # Reject anything older than 5 minutes so a captured request can't be replayed later.
    if abs(time.time() - int(timestamp)) > 300:
        return False

    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()

    return hmac.compare_digest(signature, expected)
```

> **Bandingkan tanda tangan dengan fungsi yang aman dari timing** (`timingSafeEqual` / `compare_digest`), bukan `==`. Ini tidak memakan biaya dan menghindari kelas serangan yang halus.

### Merotasi secret

Klik **Putar** untuk mengganti rahasia. Pergantian terjadi seketika: pengiriman berikutnya hanya ditandatangani dengan rahasia baru. Jika endpoint Anda aktif, terimalah **baik** rahasia lama maupun baru selama beberapa menit saat Anda menerapkan yang baru.

Mematikan penandatanganan hanya akan menghentikan pengiriman header tanda tangan.

---

## Mencoba Ulang Pengiriman yang Gagal

Secara default, pengiriman yang gagal tidak akan dicoba ulang — jika sistem Anda sedang tidak aktif pada saat itu, peristiwa tersebut akan terlewatkan.

Aktifkan **Coba ulang pengiriman yang gagal** pada webhook (di formulir buat/edit) dan kami akan terus mencoba:

| Percobaan | Kapan |
|---|---|
| 1 | Segera |
| 2 | 1 menit kemudian |
| 3 | 5 menit kemudian |
| 4 | 30 menit kemudian |
| 5 | 2 jam kemudian |

Itu mencakup sekitar **2 jam 40 menit**, sehingga webhook dapat bertahan selama jendela pemeliharaan atau gangguan singkat di pihak Anda.

**Apa yang dicoba ulang:** masalah sementara — server Anda mengembalikan kesalahan 5xx, timeout, atau kegagalan koneksi.

**Apa yang tidak dilakukan:** jika endpoint Anda menolak permintaan itu sendiri (4xx apa pun), kami tidak akan mencoba ulang — mengirimkan permintaan yang identik lagi hanya akan menghasilkan penolakan yang identik.

**Acara mana yang dicoba ulang:** webhook tag (`contact_tags_updated`), tiga acara tugas, dan ringkasan harian. Sisanya dikirim sekali, jadi untuk acara tersebut sakelar tidak memiliki fungsi apa pun. Setiap acara tetap membawa `X-Webhook-Delivery`, sehingga satu aturan deduplikasi mencakup semuanya.

> **Aktifkan percobaan ulang hanya jika endpoint Anda bersifat idempoten.** Percobaan ulang berarti peristiwa yang sama dapat tiba lebih dari sekali. Gunakan header `X-Webhook-Delivery` untuk mengenali pengulangan: header tersebut tetap sama di setiap upaya untuk satu peristiwa, sehingga Anda dapat dengan aman mengabaikan ID yang sudah Anda tangani.

Percobaan ulang berinteraksi dengan fitur nonaktif otomatis setelah kegagalan berulang (lihat [Keandalan Webhook](#webhook-reliability)) sesuai keinginan Anda: penghitung kegagalan menghitung **satu pengiriman utuh**, hanya setelah setiap percobaan ulang digunakan — bukan setiap upaya individu.

---

## Keandalan Webhook

- <span data-t="appName">Your AI Connector</span> mengirim webhook melalui koneksi aman (HTTPS). Pastikan alamat web yang Anda berikan menggunakan HTTPS.
- Jika sistem Anda mengembalikan kesalahan, pengiriman dianggap gagal.
- Pantau waktu aktif sistem penerima Anda agar tidak melewatkan peristiwa.
- Untuk alur kerja penting, aktifkan [Mencoba Ulang Pengiriman yang Gagal](#retrying-failed-deliveries), dan pertimbangkan juga mekanisme cadangan.

> **Webhook dimatikan secara otomatis setelah kegagalan berulang.** Jika URL webhook Anda gagal berulang kali (sekitar 5 kesalahan berturut-turut, atau 3 berturut-turut untuk kesalahan tipe konfigurasi), <span data-t="appName">Your AI Connector</span> secara otomatis berhenti mengirimkan peristiwa ke URL tersebut. Untuk mengaktifkannya kembali setelah endpoint Anda sehat: edit webhook tersebut dan simpan dengan URL yang diubah (perubahan URL apa pun akan mengaktifkannya kembali), atau gunakan [endpoint aktifkan kembali](../api/webhooks.md) melalui API — menyimpan kembali dengan URL yang sama tidaklah cukup. Dukungan juga dapat mengaktifkannya kembali untuk Anda.

---

## Pemecahan Masalah

| Masalah | Solusi |
|---|---|
| Webhook tidak aktif | Pertama, periksa apakah webhook tidak dalam posisi **nonaktif** pada barisnya. Kemudian pastikan peristiwa yang benar telah dipilih dan URL Anda dapat diakses dari internet. |
| Peristiwa uji berhasil tetapi peristiwa nyata tidak | Pastikan jenis peristiwa tertentu telah diaktifkan. Jika Anda mengharapkan permintaan saat tag diterapkan, perhatikan bahwa `subscribed_to_tags` tidak membatasi peristiwa webhook ke tag tertentu — ini hanya mempersempit tag mana yang menghasilkan notifikasi ringkasan percakapan. Untuk mendapatkan permintaan saat tag tertentu diterapkan, atur URL webhook pada tag tersebut di tab **Tag** agen (atau kampanye) — lihat [Webhook Pembaruan Tag Kontak](#contact-tags-updated-webhook). |
| Tidak ada yang masuk ke n8n / Make / Zapier | Anda mungkin menggunakan **URL Uji** platform tersebut, yang hanya mendengarkan satu peristiwa tepat setelah mengeklik "Dengarkan peristiwa uji." Untuk peristiwa langsung, simpan **URL Produksi** dan alihkan alur kerja ke **Aktif**. |
| Menerima peristiwa duplikat | Periksa apakah ada beberapa webhook yang mengarah ke URL yang sama. Jika **Coba ulang pengiriman yang gagal** aktif, pengulangan diharapkan terjadi kapan pun titik akhir Anda menerima peristiwa tetapi gagal merespons tepat waktu — lakukan deduplikasi pada `X-Webhook-Delivery`. |
| Pemeriksaan tanda tangan selalu gagal | Hampir selalu karena isi (body) diserialisasi ulang sebelum diperiksa. Verifikasi terhadap isi permintaan **mentah**, tanda tangan `<timestamp>.<body>`, dan pastikan Anda menggunakan rahasia (secret) saat ini jika Anda baru saja merotasinya. |
| Percobaan ulang tidak terjadi | Percobaan ulang tidak aktif kecuali diaktifkan pada webhook tertentu tersebut. Kami tidak mencoba ulang respons 4xx. |
| Blok `campaign` selalu `null` | Diharapkan jika akun Anda menggunakan agen: kontak berada pada agen, bukan kampanye. Baca blok `agent` sebagai gantinya — lihat [Format Data Webhook](#webhook-data-format). |
| Data kosong atau rusak | Verifikasi sistem penerima Anda menerima JSON. Periksa log server Anda untuk kesalahan penguraian. |
| URL Webhook mengembalikan kesalahan | Uji URL Anda dengan alat seperti Postman atau [webhook.site](https://webhook.site). |
| Webhook berhenti aktif sepenuhnya setelah pemadaman | Kegagalan berulang secara otomatis menonaktifkan webhook. Menyimpan ulang tidak mengaktifkannya kembali — perbaiki titik akhir Anda, lalu hubungi dukungan. |
| Simpan atau Uji memberikan kesalahan izin | Anda memerlukan izin "edit" Integrasi. Minta pemilik akun untuk memberikannya. |
| Daftar `subscribed_to_tags` webhook kembali kosong | `subscribed_to_tags` tidak membatasi peristiwa webhook ke tag tertentu — ini hanya mempersempit tag mana yang menghasilkan notifikasi ringkasan percakapan. Mengedit dari formulir webhook tidak lagi menghapus daftar tersebut (diperbaiki 21 Juli 2026). Jika webhook kehilangan daftarnya sebelum tanggal tersebut, atur `subscribed_to_tags` kembali melalui [API Webhook](../api/webhooks.md) — lihat [Pemicu Webhook Berbasis Tag](#tag-based-webhook-triggers). |

---

## Langkah Selanjutnya

- [Integrasi GoHighLevel](ghl-integration.md) — gunakan webhook untuk mengintegrasikan <span data-t="appName">Your AI Connector</span> dengan GHL.
- [Akses API](api-access.md) — gabungkan webhook dengan API untuk otomatisasi yang canggih.
- [Menggunakan Tag untuk Melabeli Kontak](../get-started/creating-tags.md) — siapkan tag yang memicu webhook Anda.
