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

# Webhooks

> Subscribe to signed Convertly events and verify deliveries.

Webhooks are configured from the dashboard. Convertly sends JSON payloads to active endpoints whose `event_types` include the event, so your application can update records or notify users without polling every workflow.

<div className="convertly-callout">
  Store the `whsec_` secret when you create a webhook. Convertly uses it to sign each delivery.
</div>

## What webhooks are for

Use webhooks to mark a user upload as ready, attach converted files to your own records, send a notification, or continue an automation after Convertly finishes the work.

## Event envelope

```json theme={"system"}
{
  "id": "evt_2d44218f-1a79-46af-b6a8-34a0c50f1e8d",
  "type": "conversion.completed",
  "created": 1778320800,
  "data": {
    "jobId": "job_id",
    "filename": "output.webp"
  }
}
```

## Delivery headers

| Header                | Description                      |
| --------------------- | -------------------------------- |
| `user-agent`          | `Convertly-Webhooks/1.0`         |
| `convertly-event`     | Event type.                      |
| `convertly-timestamp` | Unix timestamp used for signing. |
| `convertly-signature` | `t={timestamp},v1={hmac}`        |

## Verify signatures

The signature is an HMAC-SHA256 over `{timestamp}.{rawBody}` using the webhook secret.

```ts theme={"system"}
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyConvertlyWebhook(rawBody: string, header: string, secret: string) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const payload = `${parts.t}.${rawBody}`;
  const expected = createHmac("sha256", secret).update(payload).digest("hex");

  return timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}
```

## Subscribable events

| Event                  | When it fires                                                                                                                |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `conversion.completed` | A conversion or compression completes.                                                                                       |
| `file.uploaded`        | An original, uploaded, or converted file is stored.                                                                          |
| `media.tool.completed` | A media tool request completes, such as a thumbnail, watermark, PDF preview, audio extraction, metadata tool, or inspection. |
| `workflow.completed`   | A workflow run completes and delivers its configured webhook step.                                                           |

Convertly attempts delivery immediately, then retries after roughly 5 seconds and 25 seconds before marking a delivery failed.
