Skip to main content
A webhook is a POST to your server when something happens: a generation succeeds, fails or is canceled, or a batch completes. Runs started from the API, the studio or MCP all send events to your workspace’s endpoints. Use one for video and other long runs in a web app or a server, instead of polling. If your code can’t receive requests from the internet, such as a script or a notebook, long-poll instead. There are two ways to get them:

Hear about one run

Add webhook to the request. When the run ends, its event goes to that URL:
In a batch, give each request its own webhook. The batch’s own batch.completed event goes to a per-request URL only when every request in the batch named the same one. These events are signed with your workspace’s default webhook secret. Read it once, with a key that has generations:write, and keep it with your other secrets. It’s made the first time you read it.

Subscribe an endpoint

An endpoint gets the events of every run in your workspace, or only the types you list:
The secret is in this answer and when you rotate it, never again. Leave out events, or send ["*"], to get every type, including types added later. The URL must be https. A workspace can have up to 16 endpoints.

Events

Every event has the same envelope. data.object is the generation exactly as GET /v1/generations/{id} returns it, or the batch for batch.completed:
Output links in an event expire after 24 hours, like any other. Download the file when the event arrives, or read the generation later for fresh links.

Verify the signature

Every webhook is signed following the Standard Webhooks spec, so you can check that it came from Leap and wasn’t changed or replayed. Each request has three headers: The Standard Webhooks libraries do all of that. Verify the raw body exactly as it arrived: parsing and re-serializing the JSON changes the bytes and breaks the signature.

Answer fast, and expect retries

Answer with any 2xx within 15 seconds, and do slow work, such as downloading a video, after you answer. Anything else counts as a failure: another status, a timeout, or a redirect, which isn’t followed. Requests come from the user agent Leap-Webhooks/1.0. A failed delivery is tried again on this schedule: That’s 12 tries in all, the last about 68 hours after the first, and none later than 72 hours. An endpoint that keeps failing for 72 hours is disabled, and its disabled_reason says why. Fix it, then turn it back on with PATCH /v1/webhook_endpoints/{id} and {"disabled": false}. Delivery is at least once and in no particular order:
  • The same event can arrive more than once. Skip any webhook-id you’ve already handled.
  • An event can arrive after one that happened later. Trust the status in data.object, or read the generation for its latest state.
  • data.object is read when each delivery is sent, so its output links last 24 hours from that delivery.

Missed events

Events are kept for 30 days. List them to catch up after an outage, see how each delivery went, and send any one again:
A redelivery answers 202 with the deliveries it queued. It keeps the event’s webhook-id, so a receiver that skips duplicates handles it once. A run whose webhook you never got can always be read with GET /v1/generations/{id}, so a job that reconciles with a long-poll, or by listing your recent runs, catches anything that slipped through.

Manage endpoints

Tests and redeliveries share a budget of 100 an hour per workspace.
Last modified on October 4, 2026