Integration guide
Document callbacks
Receive extracted documents in your accounting software as soon as processing finishes. Configure one optional HTTPS callback per business in Settings → Integrations, or through the API. It covers API and dashboard uploads and approved email attachments.
Configure your endpoint
PUT /api/v1/callback
X-API-Key: YOUR_BUSINESS_API_KEY
Content-Type: application/json
{"url":"https://your-software.com/webhooks/digitizer","enabled":true,
"events":["document.processed","document.failed"]}The response includes signing_secret only on first setup or when rotate_secret is true. Store it on your server. GET /api/v1/callback returns settings and the latest 20 deliveries without the secret. A business API credential can manage this business setting; keep those credentials private.
What arrives
{
"id": "evt_example",
"type": "document.processed",
"created_at": "2026-09-22T12:00:00.000Z",
"business_id": "biz_example",
"source": {
"channel": "email",
"email_id": "mail_example",
"email_from": "[email protected]",
"email_to": "[email protected]",
"email_subject": "Invoice 1042",
"email_received_at": "2026-09-22T11:59:30.000Z"
},
"data": {
"id": "doc_example",
"filename": "invoice.pdf",
"status": "processed",
"job_id": null,
"metadata": null,
"direction": "expense",
"extraction": {
"total": 120,
"currency": "EUR"
}
}
}The data property contains the complete public document response, including review fields, duplicate matches, the upload's metadata and its direction, as available at completion. The example above is abbreviated. Source channel is api, email, or dashboard; for email it also names the message: its id, From and To addresses, subject and receipt time. The same source is on the document itself. Each new document produces one event. Reused email attachments, repeated worker attempts, and updates to an existing document do not produce additional events. Paused jobs never produce an event. Enabling a callback does not replay older documents.
Failed files
Add document.failed to events to be told when a file fails for good, after automatic retries: an unreadable or password-protected PDF, too many pages, or a processing failure. It covers API and dashboard uploads and email attachments. A callback receives document.processed only until you add it, so check type before handling an event. job_id is set for API and dashboard uploads; an email attachment has none, and source names its email. Retrying the job, or the attachment in the inbox, and failing again sends another event.
{
"id": "evt_example",
"type": "document.failed",
"created_at": "2026-09-22T12:00:00.000Z",
"business_id": "biz_example",
"source": {
"channel": "api"
},
"data": {
"job_id": "job_example",
"filename": "invoice.pdf",
"content_type": "application/pdf",
"size_bytes": 48320,
"error": {
"code": "pdf_password_required",
"message": "Remove the PDF password before uploading."
},
"source": {
"channel": "api"
},
"metadata": {
"exa": "purchase:30983"
},
"created_at": "2026-09-22T11:58:10.000Z"
}
}Verify the signature
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody is the original UTF-8 request body, before parsing JSON.
function verifyCallback(rawBody, headers, secret) {
const timestamp = headers.get("x-digitizer-timestamp") ?? "";
const signature = headers.get("x-digitizer-signature") ?? "";
if (!/^\d+$/.test(timestamp) || !/^v1=[a-f0-9]{64}$/.test(signature)) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac("sha256", secret)
.update(timestamp + "." + rawBody).digest();
return timingSafeEqual(expected, Buffer.from(signature.slice(3), "hex"));
}
// Verify first. Persist the event and deduplicate by event.id, then return 2xx.
// Perform slow accounting imports in your own background worker.Each request is a JSON POST with the headers X-Digitizer-Event-Id (the event id, also in the body), X-Digitizer-Timestamp (Unix seconds), X-Digitizer-Signature (v1=hex HMAC-SHA256 of timestamp.body) and User-Agent: Digitizer-Callbacks/1.0.
Delivery and retries
Respond with any 2xx status within 10 seconds. All other responses, redirects, and network failures retry with delays of 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, 6 hours, and 12 hours: eight attempts in total. Retries use the same event ID and body with a fresh signature timestamp. Delivery is at least once and order is not guaranteed. Deduplicate by event ID and use document duplicate metadata to review separate uploads of the same invoice.