Webhooks
Webhooks deliver asynchronous events to your HTTPS endpoint the moment something interesting happens. They are the recommended way to know when a report has finished — no polling required.
Event types
| Event | When it fires |
|---|---|
report.completed | A queued report has finished analysis successfully. |
report.failed | A report could not be completed (e.g., unreadable documents). |
document.processed | A document upload finished OCR + validation. |
document.rejected | A document failed safety / format checks and was discarded. |
report.completed payload
http
POST /your-endpoint HTTP/1.1
Content-Type: application/json
HeyVisa-Event: report.completed
HeyVisa-Signature: t=1718099274,v1=4f3a1c...
{
"id": "evt_01HXYZ...",
"type": "report.completed",
"created_at": "2026-06-11T09:21:47Z",
"data": {
"id": "rep_01HXYZ...",
"risk_score": 72,
"risk_band": "medium",
"completed_at": "2026-06-11T09:21:47Z"
}
}report.failed payload
json
{
"id": "evt_01HXYZ...",
"type": "report.failed",
"data": {
"id": "rep_01HXYZ...",
"error": {
"code": "document_unreadable",
"message": "Passport image is too blurry to process."
}
}
}document.processed payload
json
{
"id": "evt_01HXYZ...",
"type": "document.processed",
"data": {
"id": "doc_01HXYZpassport",
"type": "passport",
"status": "analysed",
"red_flags": []
}
}Delivery and retries
We attempt delivery from a fixed pool of egress IPs and expect a 2xx response within 10 seconds. Any non-2xx, timeout, or connection error is retried with exponential backoff over 24 hours.
| Attempt | Delay from previous | Cumulative |
|---|---|---|
| 1 | — | 0s |
| 2 | 30 s | 30 s |
| 3 | 2 min | 2.5 min |
| 4 | 10 min | 12.5 min |
| 5 | 1 hour | ~1h |
| 6 | 6 hours | ~7h |
| 7 | 12 hours | ~19h |
After the final failed attempt the event is marked dead-letter and appears in the dashboard under Settings → Webhooks where you can replay it manually.
Verify the signature
Every webhook includes a
HeyVisa-Signature header. See Webhook Verification for HMAC SHA-256 verification samples in Node.js and Python.Idempotency
Each event has a unique id (evt_…). Store recently processed IDs and drop duplicates — retries may deliver the same event more than once.