Log In Sign Up

Docs

Webhooks

Get a POST when a job finishes. Common use cases, handler requirements, retry policy, payload shape, and dev tips.

Converterer can POST to your endpoint when a conversion task or render job reaches a terminal state, so you don’t have to poll.

When to use webhooks

  • Long-running jobs. Video transcodes and large URL captures can take minutes. Polling wastes API calls and complicates retry logic.
  • Event-driven pipelines. Trigger downstream work (email, Slack notification, second conversion step) the moment a job is done.
  • Failure visibility. Be alerted as soon as creation_failed or delivery_failed fires, rather than discovering it on the next poll.

When a webhook is sent

A webhook fires when a job’s status moves to one of the terminal states:

  • delivered
  • creation_failed
  • delivery_failed

In-progress transitions (queuedstarted) do not fire webhooks. If you need progress reporting, you’ll have to poll.

Setting up a webhook

  1. Implement a handler at a public URL on your server.
  2. Create a webhook subscription in the dashboard, scoped to the API key whose jobs you want notified on.

You can create multiple subscriptions if different API keys should point at different endpoints. A subscription only sees jobs for its associated API key.

What your handler needs to do

  1. Accept a POST request with a JSON body.
  2. Return a 2xx response within 5 seconds, otherwise Converterer treats it as a failure and retries later.
  3. Be idempotent: the same event can be delivered more than once across retries.

A typical pattern is to do the minimum work needed to acknowledge the delivery (validate the payload, push the job ID onto your own queue), then return 200 immediately. Heavy processing happens off the webhook thread.

Retry policy

If your handler returns a non-2xx response or times out:

  • Timeout: 5-second connect, 5-second total.
  • Backoff: 5s, then 60s, then 600s (10 minutes), then ~1h55m repeating until the cutoff.
  • Cutoff: deliveries are retried for up to 48 hours, then dropped.
  • Serialized per account: only one webhook delivery per account is in flight at a time, so a slow or stuck handler won’t cause overlapping calls for your other jobs.

After the 48-hour window expires we stop trying. The job stays in its terminal state, so you can always fetch its current status via GET /convert/{id} or GET /jobs/{id}.

Payload

The webhook body is the compact form of the resource, with a webhook_id appended.

For a conversion task:

{
  "id": "9f1a8e7c-1b9b-4f0a-9d2c-1a2b3c4d5e6f",
  "status": "delivered",
  "done": true,
  "object": "conversion-task",
  "webhook_id": "d08875b3-4401-425c-acf8-21dd40c95548"
}

For a render job:

{
  "id": "fe748521-5d8f-43d8-9093-7970d2d032d7",
  "status": "delivered",
  "done": true,
  "object": "job",
  "webhook_id": "d08875b3-4401-425c-acf8-21dd40c95548"
}

webhook_id identifies the specific delivery attempt. Use it as your idempotency key, store recent IDs in a short-lived cache and ignore repeats.

Locating the result file

The webhook tells you the job finished. The file itself is in your destination’s bucket at the file_name you set on submission, or {id}.{output_format} (file conversion) / {id}.pdf (website capture) by default. Retrieve it directly from your own storage; the API doesn’t issue a signed URL for you.

If you need the latest status for a job at any time, hit GET /convert/{id} or GET /jobs/{id}. Same shape as the webhook payload.

Local development

If you’re testing locally, a tunnel like ngrok or Cloudflare Tunnel exposes your dev server at a public URL the webhook subscription can hit. Point the dashboard subscription at the tunnel URL, run your handler locally, and you can iterate without deploying.

After you ship, remember to update the subscription URL to the production endpoint.