Receive real-time notifications when conversions complete or fail.
Webhooks let your application receive an HTTP callback when conversion events occur. Instead of polling the API, OrbConvert sends a POST request with a JSON body to each endpoint you have configured. One request is sent per subscribed endpoint, and every delivery carries the same id for the event, so a receiver that sees it twice — a retry, or a second endpoint — can de-duplicate on it.
Endpoints are configured in the Developers tab of your settings; see Configuring webhooks below for the requirements, and the Developers tab to add one.
| Event | Description |
|---|---|
| conversion.completed | A conversion job finished successfully |
| conversion.failed | A conversion job failed |
| batch.completed | Every file in a batch reached a terminal state, and none failed |
| batch.failed | Every file in a batch reached a terminal state, and at least one failed |
| webhook.test | A manual test send from the Developers tab. Never emitted by a conversion — see below |
A batch event is sent once, after the last file in the batch finishes — not once per file. If you only want per-file notifications, subscribe to the two conversion.* events instead.
A conversion event carries the job it describes:
{
"event": "conversion.completed",
"id": "wh_abc123",
"created_at": "2026-09-14T10:00:00Z",
"data": {
"conversion_id": "conv_xyz789",
"status": "completed",
"from_format": "pdf",
"to_format": "docx",
"file_name": "report.pdf",
"file_size": 2457600,
"output_url": "https://api.orbconvert.com/api/files/file_abc123/download?token=eyJhbGciOiJIUzI1NiJ9...",
"user_id": "usr_42"
}
}output_url is a short-lived signed URL, not a permanent link, and it is null when the job failed before producing any output.
batch.completed and batch.failed describe the batch, not a file. Their data object has four fields:
{
"event": "batch.completed",
"id": "wh_def456",
"created_at": "2026-09-14T10:04:12Z",
"data": {
"batch_id": "bat_7f3c91",
"total": 12,
"completed": 12,
"failed": 0
}
}batch_id — the batch the files belonged tototal — how many files the batch containedcompleted — how many finished successfullyfailed — how many did nottotal always equals completed + failed. The event name follows the same rule: batch.failed is sent when at least one file failed, even if the rest succeeded.
webhook.test is sent only when you press Send test event against an endpoint. It exists so you can prove your receiver, your signature verification and your network path work before you rely on them — you do not need to run a conversion to test an integration.
{
"event": "webhook.test",
"id": "wh_9a0b1c",
"created_at": "2026-09-14T10:06:30Z",
"data": {
"message": "This is a test delivery from OrbConvert. No conversion took place."
}
}It carries no conversion_id: a test payload must never be mistaken for a conversion that actually happened, so the event name is deliberately not one of the four above. Test deliveries are signed and retried exactly like real ones, and they appear in the delivery log beside them.
Webhook endpoints are configured in the Developers tab of your settings — open the Developers tab. Each endpoint needs:
http:// is rejected, and so are internal or private addresses.When an endpoint has a signing secret, every delivery includes an x-OrbConvert-signature header: an HMAC-SHA256 of the exact request body, hex-encoded, using that secret. Verify it against the raw body you received — re-serialising the JSON before hashing will change the bytes and fail.
import hmac, hashlib
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)Two more headers identify the delivery without any cryptography: x-orbconvert-event carries the event name and x-orbconvert-delivery carries the delivery id. Endpoints created without a secret send no signature header at all, so a receiver that requires one should refuse those deliveries.
If your endpoint does not respond with 2xx within 5 seconds, OrbConvert retries up to 3 times (30s, 2min, 10min backoff). After 3 failures, the event is discarded. A retry reuses the original payload and the original event id, so a late duplicate is safe to ignore.
Redirects are not followed. A 3xx response counts as a failure — register the final URL directly. Respond 2xx as soon as you have stored the event, and do any slow work afterwards, so a busy receiver does not exhaust its retries.
Every attempt is recorded. The delivery log in the Developers tab shows each delivery's status, attempt count, response code, last error and — for one still scheduled to run — its next attempt time.
Was this page helpful?