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

# Webhooks

> Subscribe an HTTP endpoint to Roughy terminal-state events — signed, retried, and deduplicated delivery instead of polling.

## Why webhooks

Asset processing, cuts, and renders all finish asynchronously. Rather
than poll `GET /v1/assets/{id}`, `GET /v1/cuts/{id}`, or
`GET /v1/renders/{id}`, register an endpoint and Roughy POSTs you a
signed event when each one reaches a terminal state. Delivery is handled
by [Svix](https://svix.com): HMAC-signed payloads, automatic retries with
backoff, and a dashboard / CLI for inspection and replay.

Webhooks are a convenience layer, not the source of truth — if
delivery is ever degraded, the read endpoints remain authoritative.

## Managing endpoints

```bash theme={null}
# Create an endpoint subscribed to a set of event types
curl https://api.roughy.ai/v1/webhook-endpoints \
  -H "Authorization: Bearer $ROUGHY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/roughy",
    "event_types": ["cut.completed", "render.completed"]
  }'

# List your endpoints
curl https://api.roughy.ai/v1/webhook-endpoints \
  -H "Authorization: Bearer $ROUGHY_API_KEY"

# Remove one
curl -X DELETE https://api.roughy.ai/v1/webhook-endpoints/{endpoint_id} \
  -H "Authorization: Bearer $ROUGHY_API_KEY"
```

## Event catalog

| Event type              | Fired when                                                                                                                    |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `cut.completed`         | A cut finished computing and its kept-segment plan is available.                                                              |
| `cut.failed`            | A cut reached `failed`.                                                                                                       |
| `render.completed`      | A render finished and its output is available.                                                                                |
| `render.failed`         | A render failed.                                                                                                              |
| `render.cancelled`      | A render was cancelled.                                                                                                       |
| `asset.ready`           | An asset reached `ready` and is usable (cuttable and renderable). `data.previous_state` is `processing` or `pending_payment`. |
| `asset.pending_payment` | An asset finished processing but the charge couldn't be settled — it awaits a top-up.                                         |
| `asset.failed`          | An asset reached `failed` — its media could not be ingested. The reason is on the asset's `error_code` / `error_message`.     |

## Payload shape

Each delivery has a JSON body of exactly two top-level keys — `type` and
`data`:

```json theme={null}
{
  "type": "cut.completed",
  "data": { "entity_id": "<cut_id>", "asset_id": "<asset_id>" }
}
```

The Svix message id and send timestamp ride in the `svix-id` and
`svix-timestamp` headers, not in the JSON body.

## Idempotency + verification

Each message carries the standard Svix headers (`svix-id`,
`svix-timestamp`, `svix-signature`) — verify the signature with your
endpoint's signing secret, and dedupe on `svix-id`. Roughy also sets a
stable idempotency key per terminal event, so an internal retry never
delivers the same terminal state to your endpoint twice.

## Browser live-updates

For an in-app editor, first-party browser clients receive live updates
over a separate Server-Sent Events stream. Public API integrations use
webhooks.

## Related concepts

* [Cut](/concepts/cut) / [Render](/concepts/render) — the operations whose terminal states you subscribe to.
* [Errors](/concepts/errors) — the synchronous failure envelope (webhooks cover async outcomes).
