Skip to content

Webhooks

HeapStream uses webhooks to inform your application about asynchronous events that happen outside the standard API request cycle — most importantly, a video changing status (from encoding to ready, or to errored). HeapStream issues a POST request to your endpoint, and your application reacts: update your database, kick off the next step, notify a user.

Webhooks compared to polling

We advise using webhooks for monitoring video statuses instead of polling the Video API. Webhooks are significantly more efficient for both your system and HeapStream. Additionally, the video-list endpoint is rate-limited, making polling an unscalable way to track video status.

Configuring webhooks

Add the webhook URL in the project settings page.

Manage webhooks with the webhook endpoints ⧉:

  • Create ⧉{"url": "https://…"}. The URL must use HTTPS.
  • List ⧉ and delete ⧉.
  • There is no update endpoint — to change the URL, delete the webhook and create a new one.

A project can have one webhook (see Limits); once set up, it receives all of the project's events.

Receiving events

HeapStream POSTs to your URL; handle it like any route in your application. Respond with a 2xx quickly — the request allows 5 seconds to connect and 10 seconds for your response. If your processing might take longer, queue the work and respond immediately.

Retries: a delivery that fails (non-2xx, timeout, connection error) is retried up to 5 times, with the delay growing by ~10 seconds per attempt. Transient HTTP errors (429, 5xx) also get short immediate retries within each attempt. After the final failure the event is dropped — treat webhooks as a trigger, not as the source of truth, and confirm state with the video API when it matters.

Idempotency: while HeapStream strives to deliver each event once, the same event can be delivered more than once (even after your service responded 2xx). Make your handler idempotent.

Payload format

Each POST body carries one or more events under an events key:

{ "events": [  ] }

An event looks like this:

{
  "event_type": "video.created",
  "project_id": 20,
  "timestamp": "2024-10-10T10:10:10.000010+0000",
  "video": {
    "asset": {
      "duration": -1.0,
      "encoding_tier": "full",
      "errors": [],
      "id": 22,
      "normalize_audio": false
    },
    "id": 500,
    "status": "waiting_for_upload"
  }
}
Field Meaning
event_type One of the event types below.
project_id The project the event belongs to.
timestamp When the event happened (UTC).
video The video's id and status, plus a compact asset (duration, encoding tier, and any processing errors).

See the webhook payload reference ⧉ for the full schema.

Types of events

event_type Fires when
video.created A video is created — by upload, fetch, clip, or duplicate.
video.status_update The video's status changes — bytes arrived, encoding finished, or processing failed. This is the one to react to.
video.updated The video's metadata was edited.
video.deleted The video was deleted.

Securing your endpoint

Webhook payloads are currently not signed. To keep others from posting fake events to your endpoint:

  • Put an unguessable secret in the webhook URL itself (e.g. https://example.com/hooks/heapstream/<random-token>) and reject requests without it.
  • Treat the payload as a hint, not as authority: on receiving an event, read the video's current state from the API before acting on anything sensitive.