Receive real-time notifications when jobs complete or fail, instead of polling.
Webhooks let your application receive push notifications from DocuHub as events happen. Instead of repeatedly polling the /v1/jobs endpoint to check whether a conversion has finished, you register a URL and DocuHub sends an HTTP POST request to it the moment the job completes or fails.
This is faster, more efficient, and reduces unnecessary API calls against your rate limit.
DocuHub currently delivers the following event types:
| Event | Description |
|---|---|
| job.completed | Fired when an async job finishes successfully. Includes the download URL and processing duration. |
| job.failed | Fired when an async job fails after all retry attempts are exhausted. Includes the error code and message. |
Every webhook delivery is an HTTP POST request with a JSON body. Here is an example for a job.completed event:
{
"id": "evt_abc123_x7k2m9",
"type": "job.completed",
"created_at": "2026-02-18T10:00:01Z",
"data": {
"job_id": "job_xyz789",
"type": "convert",
"status": "completed",
"download_url": "https://api.docuhub.live/v1/files/xyz789",
"expires_at": "2026-02-19T10:00:01Z",
"processing_ms": 1234
}
}The id field is unique per delivery attempt and can be used for idempotency. The data object varies by event type but always contains the job_id and status.
Configure webhooks from the Developer Dashboard in three steps:
Every webhook request includes an X-DocuHub-Signature header containing an HMAC-SHA256 signature of the raw request body. Always verify this signature before processing the payload to ensure the request originated from DocuHub and was not tampered with.
JavaScript / Node.js
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Python
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)timingSafeEqual or compare_digest) to prevent timing attacks.If your endpoint does not return a 2xx status code, DocuHub retries the delivery up to 3 times with exponential backoff. After the final attempt, the event is marked as failed and can be reviewed in the Developer Dashboard.
| Attempt | Delay After Failure | Cumulative Time |
|---|---|---|
| 1 | 1 minute | 1 minute |
| 2 | 5 minutes | 6 minutes |
| 3 | 30 minutes | 36 minutes |
X-DocuHub-Signature header to ensure the request is authentic.id field to deduplicate. In rare cases (network timeouts), the same event may be delivered more than once.