Webhooks
Webhooks let Parselyze notify your application when an async job completes or fails.
How It Works
- Configure a webhook URL in the dashboard
- Optionally configure a webhook secret
- Submit async jobs as usual
- Receive
document.completedordocument.failedevents
Configuration
Set your webhook URL and optional secret in your account settings in the Parselyze dashboard.
Recommended
Always configure a webhook secret in production so you can verify the request signature.
Request Headers
Parselyze sends:
Content-Type: application/json
User-Agent: Parselyze-Webhook/1.0
If a secret is configured, Parselyze also sends:
X-Webhook-Signature: <hex_hmac_sha256_signature>
Payload
Successful job example:
{
"eventId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"eventType": "document.completed",
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"result": {
"invoice": {
"number": "INV-2025-001",
"total": 1250.75
}
},
"pageCount": 3,
"pageUsed": 3,
"pageRemaining": 1497,
"timestamp": "2026-03-31T10:30:45.123Z"
}
Failed job example:
{
"eventId": "8d0f7780-8536-51f6-c938-668877662222",
"eventType": "document.failed",
"jobId": "660f9511-f3ac-52e5-b827-557766551111",
"status": "failed",
"result": null,
"error": "Document could not be read.",
"timestamp": "2026-03-31T10:32:15.456Z"
}
Field Reference
| Field | Type | Description |
|---|---|---|
eventId | string | Unique identifier for this webhook event |
eventType | string | document.completed or document.failed |
jobId | string | Async job identifier |
status | string | completed or failed |
result | object|null | Parsed JSON when successful |
error | string | Error message when failed |
pageCount | number | Total page count, when available |
pageUsed | number | Pages consumed for the job, on success |
pageRemaining | number | Remaining quota after the job, on success |
timestamp | string | ISO timestamp for the event |
Retry Semantics
- Delivery timeout: 10 seconds
- Max delivery attempts: 3
- Retries happen on network errors, timeouts,
429, and5xx 4xxresponses other than429are not retried
Important:
- The same webhook event is retried if delivery fails
eventIdstays the same across retries for that event- Your handler should therefore be idempotent
Signature Verification
If you configured a webhook secret, compute:
- the raw request body as a string or bytes
- an HMAC-SHA256 digest using your secret
- compare it to
X-Webhook-Signature
Node.js Example
import crypto from 'crypto';
import express from 'express';
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const signature = req.header('X-Webhook-Signature');
const secret = process.env.PARSELYZE_WEBHOOK_SECRET;
if (!signature || !secret) {
return res.status(401).send('Missing signature configuration');
}
const expected = crypto.createHmac('sha256', secret).update(req.body).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString('utf8'));
console.log(event.eventType, event.jobId);
return res.status(200).send('OK');
});
Best Practices
- Verify the signature when a secret is configured
- Return
200quickly and do heavy work asynchronously - Store processed
eventIdorjobId + eventTypeto avoid duplicate handling - Log failures and monitor retry patterns