Webhooks
Register HTTPS endpoints to receive signed notifications for job lifecycle events. All webhook management routes require Bearer auth (JWT or API key).
Event types
| Type | When emitted |
|---|---|
job.queued | Job created or restarted |
job.started | Processing begins |
job.completed | All steps finished successfully |
job.failed | Job failed after final retry |
job.cancelled | Job cancelled while pending/queued |
job.updated | Extraction result manually patched |
job_run.created | Batch run created |
job_run.progress | Batch run progress update |
job_run.completed | All batch jobs finished |
job_run.failed | Batch run failed |
webhook.ping | Test ping only |
webhook.send | Manual send default type |
View the full catalog:
curl http://localhost:4000/api/webhooks/event-catalog \
-H "Authorization: Bearer YOUR_TOKEN"
Create a webhook endpoint
curl -X POST http://localhost:4000/api/webhooks \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/extractform",
"description": "Production notifications",
"deliveryMode": "AUTOMATIC",
"events": ["job.completed", "job.failed"],
"bodyFormat": "JSON"
}'
The response includes signingSecret (returned once). Store it securely for signature verification.
Delivery modes
AUTOMATIC— Subscribe to events viaevents[]. Matching events are sent automatically.MANUAL— No automatic subscriptions. Send data on demand viaPOST /api/webhooks/:id/send.
Schema binding
Schemas can reference specific webhook endpoints via webhookEndpointIds. When a job uses a schema with bound webhooks, only those endpoints receive events. See Schemas.
Webhook delivery flow
Payload format
Your server receives a POST with this JSON body:
{
"id": "webhook-event-id",
"type": "job.completed",
"data": {},
"occurredAt": "2026-01-01T12:00:00.000Z"
}
Headers:
| Header | Description |
|---|---|
Content-Type | application/json, application/xml, or application/x-www-form-urlencoded |
X-Webhook-Id | Delivery ID (use for deduplication) |
X-Webhook-Event | Event type |
X-Webhook-Timestamp | Unix seconds |
X-Webhook-Signature | t=<timestamp>,v1=<hex> HMAC-SHA256 signature |
Verify signature (Node.js)
const crypto = require('crypto');
function verifyWebhook(secret, rawBody, signatureHeader) {
const ts = signatureHeader.match(/t=(\d+)/)?.[1];
const v1 = signatureHeader.match(/v1=([a-f0-9]+)/i)?.[1];
if (!ts || !v1) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(v1, 'hex'),
Buffer.from(expected, 'hex'),
);
}
Use the raw request body (before JSON parsing). Reject requests older than ~5 minutes to prevent replay attacks.
Verify signature (Python)
import hmac
import hashlib
import re
def verify_webhook(secret: str, raw_body: bytes, signature_header: str) -> bool:
m = re.search(r"t=(\d+)", signature_header)
v = re.search(r"v1=([a-f0-9]+)", signature_header, re.I)
if not m or not v:
return False
expected = hmac.new(
secret.encode(), f"{m.group(1)}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(v.group(1), expected)
Manage webhooks
| Method | Path | Description |
|---|---|---|
GET | /api/webhooks | List endpoints |
GET | /api/webhooks/:id | Get endpoint |
PATCH | /api/webhooks/:id | Update endpoint |
DELETE | /api/webhooks/:id | Delete endpoint |
POST | /api/webhooks/:id/rotate-secret | Rotate signing secret |
POST | /api/webhooks/:id/test | Send test ping |
POST | /api/webhooks/:id/send | Manual send (MANUAL mode) |
GET | /api/webhooks/:id/deliveries | Delivery log |
POST | /api/webhooks/deliveries/:deliveryId/replay | Replay a delivery |
Subscription patterns
For AUTOMATIC endpoints, events supports:
- Exact types:
job.completed - Wildcard:
*(all job events) - Prefix wildcards:
job.*(matchesjob.queued,job.completed, etc.)
Configuration options
| Field | Description |
|---|---|
deliveryMode | AUTOMATIC or MANUAL |
bodyFormat | JSON, XML, or FORM_URLENCODED |
customHeaders | Optional map (max 20 keys; cannot override Content-Type or X-Webhook-*) |
Environment variables
| Variable | Description |
|---|---|
WEBHOOK_ENCRYPTION_KEY | 64 hex chars — encrypts signing secrets at rest |
WEBHOOK_TIMEOUT_MS | HTTP timeout per attempt (default 10000) |
WEBHOOK_MAX_ATTEMPTS | Max retry attempts (default 8) |
WEBHOOK_BACKOFF_INITIAL_MS | Initial backoff delay (default 30000) |
WEBHOOK_AUTO_DISABLE_THRESHOLD | Consecutive failures before auto-disable (default 5) |