Build an event-driven pipeline
Be told when work finishes instead of asking.
Goal. Submit documents and have Document AI call you when each one finishes, replacing the polling loop entirely.
Extraction takes around 90 seconds per page. Polling for that is workable but wasteful; at volume it is a lot of requests that mostly say "not yet". Webhooks invert it — you register an endpoint once and receive a signed POST per completion.
Before you start
An API key, exported as
$DOCAI_API_KEY.A publicly reachable HTTPS endpoint. It must be reachable from the platform, so
localhostwill not do during development — use a tunnel.Owner or Admin access to the portal, to configure the endpoint and read the signing key.
Step 1 — Register your endpoint
Webhook endpoints are configured in the portal, not through the API.
Sign in as Admin or Owner.
Settings → Edit Account Information.
Enter your URL in Webhook URL and save.
In the same panel, Reveal the Webhook Signing Key (
whk_…) and store it asWEBHOOK_PRIVATE_KEY.
Endpoints are account-wide — every completion goes to every configured URL. There is no per-event subscription, and extraction and classification requests cannot override the destination. Generation is the exception: its request accepts a per-job webhookUrl.
Step 2 — Verify signatures before trusting anything
Your endpoint is a public URL that receives document data. The x-signature header is the only thing separating a genuine delivery from anyone who finds the address.
Verify against the raw bytes, not a re-serialised object. JSON.stringify(req.body) after your framework has parsed the request can reorder keys or change spacing, which invalidates a signature that was actually fine. Capturing rawBody as above avoids the whole class of problem.
Step 3 — Make the handler idempotent
Deliveries retry, so the same event will sometimes arrive twice. Every payload carries an eventId:
Design for at-least-once delivery. Deduplicating on eventId is far simpler than trying to make the platform deliver exactly once.
Step 4 — Acknowledge quickly, process afterwards
Respond 200 as soon as you have verified and stored the event. Do the real work on a queue.
Two reasons. A slow endpoint eventually times out and the delivery is treated as failed even though you received it. And 4xx responses are terminal — the platform stops retrying that destination rather than backing off. Returning 4xx because your database was briefly unavailable permanently discards the event.
2xx
Delivered
4xx
Permanent failure — retries stop
5xx or timeout
Retried with backoff
Retries are 3 attempts with exponential backoff starting at 30 seconds, capped at 8 minutes. Deliveries stuck in processing can be retried after 24 hours. See Webhooks & Integrations.
Step 5 — Submit work
Nothing changes about submission. Use the asynchronous endpoints and ignore the returned ID if you like — the webhook will bring it back.
Step 6 — Handle grouped completions
When one file yields several documents, you get one delivery per child, not one for the set:
Do not assume they arrive in order. Count distinct extractionGroupIndex values against extractionGroupTotal to decide when a group is complete, then fetch the whole thing with GET /document-extractions/group/{id} — see Extract many documents at once.
Batch jobs also emit a summary-level delivery with webhookType: "batch_extraction", which is separate from the per-document events.
Step 7 — Monitor
The Webhook Monitor in the portal lists every delivery with its status and attempt count, and lets you retrigger one by hand after fixing a downstream problem. Use it when something did not arrive — it will tell you whether the platform tried.
An extraction record carries a webhookStatus object. On an account with no webhook URL configured it reads {"status": "Failed", "processingAttempts": 0} — zero attempts, nothing wrong. Confirm an endpoint is actually configured before investigating a "failure".
When it goes wrong
No deliveries at all
No URL configured, or not publicly reachable
Check Settings → Edit Account Information; test from outside your network
Every signature mismatches
Verifying a re-serialised body, or the wrong key
Verify raw bytes; re-reveal the signing key
Deliveries stop after one failure
You returned 4xx
Return 5xx for transient problems so retries continue
Same document processed twice
No idempotency
Deduplicate on eventId
webhookStatus: Failed, 0 attempts
No endpoint configured
Configure one
Related pages
Webhook payloads — every payload shape and the full signature contract.
Webhooks & Integrations — the Monitor, retry schedule and retrigger.
Extract asynchronously and poll — the alternative when you cannot host an endpoint.
Last updated

