Why webhooks
Asset processing, cuts, and renders all finish asynchronously. Rather than pollGET /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: 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
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:
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.