> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yotel.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks overview

> Subscribe to real-time events from your campaigns, calls, and agents.

Webhooks deliver platform events to your endpoint as signed HTTPS
POSTs. One subscription covers one or more event types; Yotel fans
out each event to every matching subscription.

## Subscribe

<Info>
  Subscriptions can be managed via the dashboard UI or programmatically
  via the [Webhook Management API](/api-reference/webhooks/management).
  Both paths use Supabase JWT authentication (not API keys) and require
  the `webhooks:manage` permission.
</Info>

1. Dashboard → **Developer → Webhooks**
2. Click **New subscription**
3. Enter your HTTPS URL (HTTP is rejected at the DB layer)
4. Pick event types from the [catalog](/webhooks/event-catalog)
5. On save, copy the `signing_secret` — **shown once**

You can have multiple subscriptions — e.g. one for `call.ended` to
your warehouse, another for `campaign.paused` to your on-call Slack.

## Event envelope

Every delivery is a POST with:

```http theme={null}
POST /your-url HTTP/1.1
Content-Type: application/json
X-Yotel-Event: call.ended
X-Yotel-Delivery: 3c8f4a9b-7d11-4c8d-9a2e-1b3e5f6a7c12
X-Yotel-Timestamp: 1744934400
X-Yotel-Signature: sha256=abc123…

{
  "event_id": "1f2e...",
  "event_type": "call.ended",
  "timestamp": 1744934400,
  "data": {
    "call_id": "c-1234",
    "campaign_id": "camp-567",
    "lead_id": "l-890",
    "hangup_cause": "NORMAL_CLEARING",
    "talk_duration_s": 42,
    "disposition": "interested",
    "recording_url": "https://storage.googleapis.com/yotel-recordings/..."
  }
}
```

## Expectations for your endpoint

|                   | Requirement                                                       |
| ----------------- | ----------------------------------------------------------------- |
| Protocol          | **HTTPS** — `http://` URLs are rejected at subscribe time         |
| Timeout           | Respond within **10s** — we cancel the request after that         |
| Success           | Return **2xx** to mark the delivery delivered                     |
| Temporary failure | Return **408, 429, or 5xx** → we retry                            |
| Permanent failure | Return **other 4xx** → we dead-letter immediately (no retry)      |
| Ordering          | **None guaranteed** — key on `event_id` for idempotent processing |

## Retries

Failed deliveries retry on this schedule (±10% jitter):

| Attempt | Delay                  |
| ------- | ---------------------- |
| 1 → 2   | +5s                    |
| 2 → 3   | +30s                   |
| 3 → 4   | +3m                    |
| 4 → 5   | +15m                   |
| 5 → 6   | +1h                    |
| 6 → 7   | +6h                    |
| 7       | DEAD — no more retries |

**Total retry window: \~7.5 hours.** If your endpoint is down longer
than that for a specific event, it's gone from the queue — you'll
need to reconcile state from your side using the relevant REST
endpoints.

After **20 consecutive failures AND no successful delivery in 24h**
your subscription is auto-disabled. You'll need to manually re-enable
from the dashboard.

## Troubleshooting

Your dashboard's **Webhooks → Delivery log** shows every delivery
attempt with HTTP status, response snippet, and duration. If signatures
don't verify on your side, 95% of the time it's clock skew — see
[signature verification](/webhooks/signature-verification).

## Next

* [Event catalog](/webhooks/event-catalog) — every event + payload shape
* [Signature verification](/webhooks/signature-verification) — reference verifier implementations
* [Troubleshooting](/webhooks/troubleshooting) — common failures
