
# API Webhook

Webhook memungkinkan platform untuk memberi tahu sistem Anda yang lain saat sesuatu terjadi — kontak baru, balasan, janji temu yang dipesan, dan banyak lagi. API ini mengelola **langganan** itu sendiri: URL mana yang menerima peristiwa apa. Untuk cara menerima dan memverifikasi payload yang didapatkan endpoint Anda, lihat [Webhook](../integrations/webhooks.md).

Semua jalur di bawah ini bersifat relatif terhadap URL dasar API:

```
https://api.youraiconnector.com/v1
```

Setiap permintaan harus diautentikasi. Lihat [Autentikasi](authentication.md) untuk empat metode yang diterima. Contoh di sini menggunakan header `X-API-Key` (dan satu bentuk parameter kueri untuk cURL).

::: note
**Catatan:** Webhook harus diaktifkan untuk akun Anda. Jika belum, endpoint ini akan mengembalikan `403`.
:::


---

## Cara menangani langganan

Setiap langganan memiliki `id` dan `name` opsional. Keduanya dapat digunakan sebagai `{webhookId}` di jalur untuk pembaruan, penghapusan, pengujian, kesehatan, dan pengaktifan kembali.

> **Gunakan nama.** ID langganan bersifat posisional, sehingga dapat bergeser setelah langganan lain dihapus. Jika Anda menetapkan `name` yang stabil saat membuat langganan, alamatkan berdasarkan nama untuk menghindari hal yang tidak diinginkan.

---

## Mencantumkan langganan

`GET /webhooks`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/webhooks?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/webhooks",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Respons**

```json
{
  "success": true,
  "webhooks": [
    {
      "id": "0",
      "name": "Order updates hook",
      "url": "https://hooks.example.com/incoming",
      "subscribed_to": ["Contact Created", "Replies"],
      "subscribed_to_tags": [],
      "created_at": "2026-06-09T12:00:00.000Z",
      "signing_enabled": true,
      "signing_secret_created_at": "2026-07-15T09:30:00.000Z",
      "retries_enabled": true,
      "enabled": true,
      "apply_to_sub_accounts": false
    }
  ]
}
```

`signing_enabled` dan `retries_enabled` adalah pilihan keikutsertaan per langganan, keduanya nonaktif kecuali Anda mengaktifkannya. Lihat [Payload bertanda tangan](#signed-payloads) dan [Percobaan ulang](#retries).

`apply_to_sub_accounts` adalah keikutsertaan pewarisan agensi — lihat [Satu langganan untuk semua akun klien](#one-subscription-for-all-client-accounts-agencies). Nonaktif secara default, dan tidak aktif pada akun yang tidak memiliki akun klien.

`enabled` adalah sakelar hidup/mati langganan — lihat [Mematikan langganan](#switching-a-subscription-off). Langganan yang dimatikan tetap tercantum di sini.

Rahasia penandatanganan itu sendiri tidak pernah disertakan di sini — baca dari [`GET /webhooks/{id}/signing-secret`](#read-the-signing-secret).

---

## Mencantumkan jenis peristiwa yang dapat dilanggan

Mengembalikan string persis yang dapat Anda gunakan di `subscribed_to`. Gunakan ini untuk menemukan nama peristiwa yang valid daripada melakukan hard-coding.

`GET /webhooks/events`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/webhooks/events" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/events", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/webhooks/events",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Respons**

Responsnya adalah `{"success": true, "events": [...]}`, di mana `events` saat ini menampung 22 string eksak: Contact Created, Human Alerted, Appointment Booked, Replies, Reads, Deliveries, Credits Spent, Credits Recharged, Low Credit Balance, Contact Paused, Contact Do Not Disturb, Contact Unarchived, New Message, Contact Resumed, Chat Concluded, Task Created, Task Updated, Task Completed, Daily Summary Created, Channel Connected, Broadcast Started, dan Broadcast Completed (Channel Connected diterima di `subscribed_to` tetapi tidak ada yang memancarkannya saat ini, jadi jangan membangun fitur berdasarkan hal tersebut).

Untuk mengetahui arti setiap peristiwa dan kode `event` yang dikirimkannya dalam payload, lihat [22 Peristiwa Webhook](../integrations/webhooks.md#the-22-webhook-events). Titik akhir ini adalah daftar otoritatif setiap saat — bacalah secara langsung alih-alih melakukan hard-coding pada nama-namanya.

---

## Membuat langganan

`POST /webhooks`

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `url` | Ya | URL HTTPS yang akan menerima payload peristiwa melalui `POST`. Harus dapat diakses secara publik. |
| `subscribed_to` | Ya | Array nama peristiwa yang tidak kosong (lihat `/webhooks/events`). |
| `name` | Tidak | Nama tampilan. Juga dapat digunakan sebagai `{webhookId}` nantinya. Default-nya adalah nama dengan stempel waktu. |
| `subscribed_to_tags` | Tidak | ID tag yang mempersempit tag mana yang menghasilkan notifikasi ringkasan percakapan. Ini tidak membatasi peristiwa langganan ke tag tersebut — untuk mendapatkan permintaan saat tag tertentu diterapkan, atur URL webhook pada tag tersebut di tab **Tag** agen (atau kampanye). |
| `retries_enabled` | Tidak | Boolean, default-nya `false`. Ikut serta dalam [percobaan ulang](#retries) pengiriman yang gagal. |
| `generate_signing_secret` | Tidak | Boolean, default-nya `false`. Buat [rahasia penandatanganan](#signed-payloads) HMAC dengan langganan. Rahasia dikembalikan satu kali, sebagai `signing_secret` tingkat atas pada respons. |
| `enabled` | Tidak | Boolean, default-nya `true`. Teruskan `false` untuk membuat langganan dalam keadaan nonaktif. Lihat [Mematikan langganan](#switching-a-subscription-off). |
| `apply_to_sub_accounts` | Tidak | Boolean, default-nya `false`. Pada akun agensi, `true` membuat langganan ini juga menerima peristiwa dari setiap akun klien — lihat [Satu langganan untuk semua akun klien](#one-subscription-for-all-client-accounts-agencies). |

> **Aturan URL:** URL harus menggunakan `https://` dan dapat diakses secara publik. `http://` biasa, `localhost`, alamat jaringan privat, dan alamat internal platform akan ditolak dengan `400`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/incoming",
    "subscribed_to": ["Contact Created", "Replies"],
    "name": "Order updates hook"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://hooks.example.com/incoming",
    subscribed_to: ["Contact Created", "Replies"],
    name: "Order updates hook",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/webhooks",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "url": "https://hooks.example.com/incoming",
        "subscribed_to": ["Contact Created", "Replies"],
        "name": "Order updates hook",
    },
)
data = res.json()
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "1",
  "webhook": {
    "id": "1",
    "name": "Order updates hook",
    "url": "https://hooks.example.com/incoming",
    "subscribed_to": ["Contact Created", "Replies"],
    "subscribed_to_tags": [],
    "created_at": "2026-06-09T12:00:00.000Z"
  }
}
```

---

## Memperbarui langganan

Berikan setidaknya satu dari `url`, `subscribed_to`, `name`, `subscribed_to_tags`, `retries_enabled`, `enabled`, atau `apply_to_sub_accounts`. Bidang yang dihilangkan akan mempertahankan nilai saat ini. `subscribed_to` dan `subscribed_to_tags` adalah penggantian, bukan penggabungan.

`PUT /webhooks/{webhookId}`

> Memperbarui langganan tidak akan pernah mengganggu rahasia penandatanganannya — kelola hal tersebut melalui [rute rahasia penandatanganan](#signed-payloads).

> Saat URL berubah, pengiriman untuk URL baru akan diaktifkan kembali secara otomatis, memberikan titik akhir yang sebelumnya gagal kesempatan baru.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/Order%20updates%20hook" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/v2/incoming",
    "subscribed_to": ["Replies", "Chat Concluded"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  `https://api.youraiconnector.com/v1/webhooks/${encodeURIComponent("Order updates hook")}`,
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://hooks.example.com/v2/incoming",
      subscribed_to: ["Replies", "Chat Concluded"],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/webhooks/Order updates hook",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "url": "https://hooks.example.com/v2/incoming",
        "subscribed_to": ["Replies", "Chat Concluded"],
    },
)
data = res.json()
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0",
  "webhook": {
    "id": "0",
    "name": "Order updates hook",
    "url": "https://hooks.example.com/v2/incoming",
    "subscribed_to": ["Replies", "Chat Concluded"],
    "subscribed_to_tags": [],
    "created_at": "2026-06-09T12:00:00.000Z"
  }
}
```

ID atau nama yang tidak dikenal akan mengembalikan `404` dengan `{ "success": false, "error": "Webhook not found" }`.

---

## Menghapus langganan

Menghapus langganan sehingga URL-nya berhenti menerima payload. Penghitung kesehatan pengiriman akan diatur ulang, sehingga menambahkan kembali URL yang sama nantinya akan dimulai dengan catatan bersih.

`DELETE /webhooks/{webhookId}`

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/webhooks/0" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0", {
  method: "DELETE",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/webhooks/0",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Respons**

```json
{
  "success": true
}
```

---

## Mengirim payload uji

Mengirim payload sampel ke URL langganan agar Anda dapat memverifikasi penerima Anda dari ujung ke ujung. Secara opsional, berikan `event` untuk mengontrol jenis peristiwa mana yang disimulasikan oleh sampel tersebut. Pengiriman uji tidak akan pernah memengaruhi penghitung kesehatan langganan.

`POST /webhooks/{webhookId}/test`

Respons selalu mengembalikan `200` dan melaporkan hasil dengan flag `delivered` — uji yang gagal **tidak** mengembalikan status kesalahan. Saat `delivered` adalah `false`, respons menyertakan detail kegagalan.

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `event` | Tidak | Jenis peristiwa untuk disimulasikan (harus salah satu dari `/webhooks/events`). Default-nya adalah peristiwa pengiriman. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/test?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "event": "Contact Created" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0/test", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ event: "Contact Created" }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/webhooks/0/test",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"event": "Contact Created"},
)
data = res.json()
```

**Respons** (terkirim)

```json
{
  "success": true,
  "webhook_id": "0",
  "delivered": true
}
```

**Respons** (gagal)

```json
{
  "success": true,
  "webhook_id": "0",
  "delivered": false,
  "failure_type": "permanent",
  "status_code": 404,
  "error_message": "Request failed with status code 404"
}
```

`failure_type` adalah salah satu dari `permanent`, `temporary`, `timeout`, `network`, atau `unknown`.

---

## Periksa kesehatan pengiriman

Mengembalikan catatan kesehatan pengiriman untuk URL langganan: berapa banyak pengiriman yang berhasil dan gagal, apakah pengiriman saat ini dijeda setelah kegagalan berulang, dan detail kegagalan terbaru. Mengembalikan `"health": null` jika belum ada pengiriman yang dicoba.

`GET /webhooks/{webhookId}/health`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/webhooks/0/health" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0/health", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/webhooks/0/health",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0",
  "url": "https://hooks.example.com/incoming",
  "health": {
    "consecutive_failures": 0,
    "total_failures": 2,
    "total_successes": 120,
    "is_disabled": false,
    "disabled_at": null,
    "disabled_reason": null,
    "last_failure": null,
    "last_success_at": "2026-06-09T12:00:00.000Z",
    "created_at": "2026-05-01T08:00:00.000Z",
    "updated_at": "2026-06-09T12:00:00.000Z"
  }
}
```

Ketika `is_disabled` adalah `true`, pengiriman ke URL telah dijeda secara otomatis setelah kegagalan berulang. Perbaiki penerima Anda, lalu aktifkan kembali (di bawah).

---

## Aktifkan kembali pengiriman

Melanjutkan pengiriman untuk webhook yang URL-nya dijeda secara otomatis setelah kegagalan berulang. Ini mengatur ulang tanda jeda dan penghitung kegagalan tetapi **tidak** mencoba pengiriman — gunakan endpoint pengujian setelahnya untuk memastikan penerima Anda sudah sehat kembali.

`POST /webhooks/{webhookId}/reenable`

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/reenable?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/webhooks/0/reenable", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/webhooks/0/reenable",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0"
}
```

---

## Mematikan langganan

`enabled` adalah sakelar hidup/mati langganan itu sendiri. Mematikannya akan menghentikan pengiriman sambil tetap menjaga URL, daftar peristiwa, dan rahasia penandatanganan tetap utuh.

```bash
# Off
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

# Back on
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
```

- **Tidak ada berarti aktif.** Langganan yang dibuat sebelum bidang ini ada tidak memiliki nilai `enabled` yang tersimpan dan mengirimkan data secara normal. `GET /webhooks` selalu melaporkan boolean konkret.
- Langganan yang dimatikan **tetap tercantum** oleh `GET /webhooks` — itulah cara Anda menemukannya untuk menghidupkannya kembali.
- [Percobaan ulang](#retries) yang diantrekan sebelum dimatikan tidak akan dilanjutkan: percobaan ulang membaca ulang langganan pada saat pengiriman dan membatalkannya jika langganan tersebut dimatikan.
- Tidak ada yang ditekan saat dimatikan akan diputar ulang saat Anda menghidupkannya kembali.

> Berbeda dari penonaktifan otomatis setelah kegagalan berulang, yang dilaporkan oleh [`GET /webhooks/{id}/health`](#check-delivery-health) sebagai `is_disabled` dan dibersihkan dengan [`POST /webhooks/{id}/reenable`](#re-enable-delivery). `enabled` adalah sakelar akun; `is_disabled` adalah sakelar kami. Keduanya tidak saling menggantikan — langganan harus dalam keadaan aktif dan tidak dinonaktifkan secara otomatis agar dapat mengirimkan data.

---

## Satu langganan untuk semua akun klien (agensi)

Pada akun agensi, atur `apply_to_sub_accounts: true` pada langganan (saat pembuatan atau melalui `PUT`) dan langganan tersebut juga akan menerima peristiwa yang terjadi pada setiap akun klien agensi — satu titik akhir mencakup seluruh agensi, alih-alih membuat ulang langganan pada setiap akun klien.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"apply_to_sub_accounts": true}'
```

Cara kerjanya:

- **Blok `user` membedakan akun satu sama lain.** Blok `user` pada setiap payload mengidentifikasi akun tempat peristiwa tersebut benar-benar terjadi, sehingga penerima Anda dapat melakukan perutean per klien.
- **Pengaturan langganan agensi sendiri berlaku di mana saja.** Daftar peristiwanya, [rahasia penandatanganan](#signed-payloads), dan keikutsertaan [percobaan ulang](#retries) juga digunakan untuk pengiriman yang diwariskan.
- **Langganan akun klien sendiri ke URL yang sama lebih diutamakan.** Jika akun klien memiliki langganannya sendiri yang mengarah ke URL yang sama, langganan tersebut yang digunakan untuk peristiwa akun itu — peristiwa yang sama tidak akan pernah dikirim dua kali ke satu titik akhir.
- **Akun klien tidak melihatnya.** Langganan yang diwariskan tidak muncul dalam daftar webhook akun klien sendiri, dan klien tidak dapat mematikannya — hanya agensi yang mengelolanya.
- **Kesehatan pengiriman dilacak per akun klien.** Titik akhir yang terus gagal akan dinonaktifkan secara otomatis untuk akun yang pengirimannya gagal, bukan untuk seluruh agensi.
- **`subscribed_to_tags` tidak diwariskan.** Daftar tag merujuk pada tag agensi itu sendiri, yang tidak ada pada akun klien — pembatasan ringkasan percakapan hanya berlaku untuk peristiwa agensi itu sendiri.
- **Tidak aktif di tempat lain.** Pada akun yang tidak memiliki akun klien, flag tersebut tersimpan dengan baik dan tidak melakukan apa pun.

---

## Header pada setiap pengiriman

Tiga header ini dikirim pada setiap pengiriman, terlepas dari apakah langganan ditandatangani atau tidak:

| Header | Arti |
|---|---|
| `X-Webhook-Delivery` | ID stabil untuk peristiwa logis. Identik di seluruh percobaan ulang — lakukan deduplikasi berdasarkan ID ini. |
| `X-Webhook-Attempt` | Nomor percobaan berbasis 1. |
| `X-Webhook-Event` | Nama peristiwa. |

---

## Payload bertanda tangan

Penandatanganan bersifat opsional, nonaktif secara default, dan diatur per langganan. Ketika langganan memiliki rahasia penandatanganan, setiap pengiriman membawa dua header lagi di atas tiga header yang dikirim pada setiap pengiriman (`X-Webhook-Delivery`, `X-Webhook-Attempt`, dan `X-Webhook-Event`):

| Header | Arti |
|---|---|
| `X-Webhook-Signature` | `v1=<hex>` — HMAC-SHA256 dari string `"<timestamp>.<raw request body>"`, yang dikunci dengan rahasia penandatanganan per-webhook yang Anda buat dan rotasi di `GET/POST/DELETE /v1/webhooks/{webhookId}/signing-secret`. |
| `X-Webhook-Timestamp` | Waktu pengiriman, dalam detik Unix. Terikat ke dalam tanda tangan, sehingga tidak dapat diubah secara independen. |

Untuk memverifikasi, hitung ulang HMAC-SHA256 atas body mentah dengan rahasia Anda dan bandingkan dengan header. Verifikasi terhadap body permintaan **mentah**. Melakukan serialisasi ulang JSON yang telah diurai akan mengubah byte dan merusak perbandingan. Tolak pengiriman yang stempel waktunya berada di luar jendela kesegaran (300 detik adalah default yang masuk akal) untuk mencegah pemutaran ulang, dan bandingkan dengan fungsi yang aman terhadap waktu.

Lihat [Payload Bertanda Tangan](../integrations/webhooks.md#signed-payloads-verifying-a-webhook-really-came-from-us) untuk contoh verifikasi Node dan Python lengkap.

> **Penandatanganan tidak sama dengan autentikasi API.** REST API itu sendiri melakukan autentikasi dengan kunci API alih-alih OAuth (OAuth 2.1 memang ada untuk server MCP yang Anda daftarkan sebagai alat bot), dan belum ada paket SDK npm atau PyPI resmi — panggil titik akhir dengan klien HTTP apa pun.

### Membaca rahasia penandatanganan

`GET /webhooks/{id}/signing-secret`

```bash
curl "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": true,
  "signing_secret": "whsec_1a2b3c...",
  "signing_secret_created_at": "2026-07-15T09:30:00.000Z"
}
```

Saat penandatanganan nonaktif, `signing_enabled` adalah `false` dan `signing_secret` adalah `null`.

### Membuat atau merotasi rahasia penandatanganan

`POST /webhooks/{id}/signing-secret`

Membuat rahasia (mengaktifkan penandatanganan) atau mengganti yang sudah ada. Mengembalikan rahasia baru.

```bash
curl -X POST "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": true,
  "signing_secret": "whsec_9f8e7d...",
  "signing_secret_created_at": "2026-07-15T10:00:00.000Z"
}
```

Rotasi langsung berlaku — pengiriman berikutnya hanya ditandatangani dengan rahasia baru. Terima kedua rahasia tersebut untuk sementara saat Anda meluncurkan perubahan ke endpoint langsung.

Anda juga dapat membuat rahasia pada saat pembuatan dengan meneruskan `"generate_signing_secret": true` ke `POST /webhooks`; respons kemudian menyertakan kolom `signing_secret` tingkat atas.

### Nonaktifkan penandatanganan

`DELETE /webhooks/{id}/signing-secret`

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/webhooks/0/signing-secret?apiKey=YOUR_API_KEY"
```

**Respons**

```json
{
  "success": true,
  "webhook_id": "0",
  "signing_enabled": false
}
```

> Ketiga rute rahasia penandatanganan memerlukan izin **edit** Integrasi, termasuk `GET` — rahasia adalah kredensial yang dapat memalsukan pengiriman, sehingga tidak diekspos ke peran yang hanya dapat membaca (read-only).

---

## Percobaan ulang

Opsional, nonaktif secara default, dan diatur per langganan melalui boolean `retries_enabled` pada `POST /webhooks` atau `PUT /webhooks/{id}`.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/webhooks/0?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"retries_enabled": true}'
```

Jika diaktifkan, pengiriman yang gagal akan dicoba ulang pada **1m, 5m, 30m, dan 2j** setelah percobaan pertama (sekitar 2j40m cakupan).

- **Dicoba ulang:** respons 5xx, timeout, dan kegagalan koneksi.
- **Tidak dicoba ulang:** semua 4xx. Penerima menolak permintaan itu sendiri, jadi memutar ulang tanpa perubahan hanya akan menghasilkan penolakan yang sama.

Percobaan ulang memungkinkan pengiriman duplikat — titik akhir yang telah memproses peristiwa tetapi kehabisan waktu sebelum merespons akan melihatnya lagi. Lakukan deduplikasi pada `X-Webhook-Delivery`, yang bersifat konstan di seluruh percobaan. Inilah sebabnya mengapa percobaan ulang bersifat opsional.

Penghitung [delivery-health](#check-delivery-health) menghitung keseluruhan pengiriman, bukan setiap percobaan: kegagalan hanya dicatat sekali setelah setiap percobaan ulang habis, jadi mengaktifkan percobaan ulang tidak membuat pemicu penonaktifan otomatis terjadi lebih cepat.

---

## Kesalahan

Semua kesalahan menggunakan amplop standar:

```json
{
  "success": false,
  "error": "Webhook not found"
}
```

Kasus umum: URL yang tidak diizinkan, `subscribed_to` kosong/tidak valid, atau kolom yang hilang mengembalikan `400`; id atau nama yang tidak dikenal mengembalikan `404`; dan `403` berarti webhook tidak diaktifkan untuk akun Anda. Lihat [Kesalahan](errors-and-pagination.md) untuk daftar lengkapnya.

---

## Langkah berikutnya

- [Webhook (menerima payload)](../integrations/webhooks.md) — siapkan penerima Anda dan pahami bentuk payload.
- [Autentikasi](authentication.md) — empat cara untuk mengautentikasi permintaan.
- [Error & Batas Kecepatan](errors-and-pagination.md) — kode status dan batas 300 req/mnt.
