Verinode Developer
Webhooks
Receive events in real time.
Register an HTTPS endpoint to receive events as they happen. Requires the webhooks scope; the signing secret is returned once. Up to 10 endpoints per operator — an eleventh returns 409 too_many_endpoints.
curl -X POST https://api.verinode.ai/v1/webhook-endpoints \
-H "Authorization: Bearer $KEY" -H "content-type: application/json" \
-d '{ "url": "https://example.com/hooks", "events": ["job.created","export.completed"] }'
→ 201 { "id": "…", "secret": "whsec_…", "status": "active" }
#Event catalog
Five event types fire today. The list is deliberately exactly what has a live producer — you can never subscribe to something that never arrives. Subscribe with ["*"] to receive all of them.
| job.created | A job was created. |
| client.created | A client was created. |
| ingestion.completed | A document you pushed finished extracting. |
| ingestion.failed | A document you pushed failed extraction. |
| export.completed | An export is ready to download. |
#Only what you pushed
ingestion.completed and ingestion.failed fire only for documents ingested through POST /v1/documents. A document the operator emailed in or uploaded through the Verinode dashboard fires nothing — it never reaches your endpoint.
This is a privacy boundary, not a gap: the operator's own paperwork is their business, and a partner integration is not entitled to a feed of it. Design for it. If you need to know about documents you didn't send, poll the read endpoints with updated_since — the records that extraction produces show up there like any other change.
#Verifying signatures
Each delivery carries Verinode-Signature: t=<unix>,v1=<hmac>. Recompute HMAC_SHA256(secret, "<t>.<raw body>") and compare:
import hmac, hashlib
def verify(secret, body, header):
parts = dict(p.split("=") for p in header.split(","))
expected = hmac.new(secret.encode(), f"{parts['t']}.{body}".encode(),
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])
#Delivery
Deliveries retry on failure (1m → 24h) and an endpoint failing for 7 straight days auto-disables. Only public HTTPS URLs are accepted (validated at registration and at every delivery). Can't run a listener? Poll GET /v1/outbound-events instead.