API v1 documentation
Recipes
Task-based integration guides for the workflows developers build first.
Upload and poll
Use this pattern when your application controls the user flow and can show processing state directly. Upload with an idempotency key, store the returned document ID, then poll until the document is no longer pending.
- Upload the file with
POST /documents. - Store
data.id,data.mode,data.processing_lane, and yourIdempotency-Key. - Poll
GET /documents/{document}untilstatusiscompleted,error, orblocked. - Read
GET /documents/{document}/extractionswhen completed.
switch (document.data.status) {
case "completed":
// Read /documents/{document}/extractions and continue mapping.
break;
case "pending":
// Poll again with backoff, or wait for a webhook.
break;
case "blocked":
case "error":
// Show a clear recovery path instead of silently retrying forever.
break;
}
For generic live extraction, the accepted response normally reports latest_extraction_run.credit_cost: 1 and credits_charged: 1. A specialized profile can use a different rate. Keep observing the document after 201: analysis calculates usage as credit_cost × started 10-page bands, and a later band that available credits cannot cover changes the document to blocked_reason: "page_band_insufficient_credits" with zero net usage.
The batch lane is available to eligible accounts. Use processing_lane=batch for delay-tolerant work; its lower-priority capacity can take longer to start while returning the same result shape and lifecycle events as standard processing. If batch is unavailable for the account, the upload returns 422 with code=validation_failed and a processing_lane validation error.
Generate only a thumbnail
Use thumbnail mode when your archive, inbox, or media workflow only needs a visual identifier. The upload stays asynchronous and emits the normal document webhooks, but it does not run OCR or extraction and has zero credit usage.
- Upload with
processing_mode=thumbnailand a stable idempotency key. - Store
data.idand poll the document or wait fordocument.completed. - Download
GET /documents/{document}/thumbnailafter completion. - Treat
document.failedorstatus: "error"as a thumbnail failure and inspectprocessing_error.
curl -sS -X POST "https://www.exdata.app/api/v1/documents" \
-H "Authorization: Bearer $EXDATA_API_TOKEN" \
-H "Idempotency-Key: archive-video-thumbnail-1048" \
-F "file=@./inspection-video.mp4" \
-F "processing_mode=thumbnail"
For videos, the thumbnail is a representative decoded frame stored as JPEG. Completed thumbnail-only documents have no persisted previews or extraction fields, and latest_extraction_run is null.
Test mode
Use a test-mode token while building and QA testing. The request shape, document lifecycle, extraction fields, idempotency behavior, and webhook payloads match live mode; responses include mode: "test" and extraction runs report credits_charged: 0.
| What to test | Expected behavior | Go-live gate |
|---|---|---|
| Representative PDFs | Fields appear with useful candidates. | Your mapper handles missing optional fields. |
| Duplicate upload retry | Same idempotency key returns the stored response. | Your integration can safely retry network failures. |
| Webhook receiver | Signature verification and delivery dedupe pass. | Your receiver stores processed delivery IDs. |
| Limit response | 429 with test_mode_limit_exceeded. | Your integration shows a clear message. |
Webhook receiver
Use webhooks when your system should react without polling. Verify X-Signature against the signed timestamp, delivery ID, event, and exact raw request body before parsing JSON. Reject stale timestamps, then dedupe by X-Delivery.
- Configure the endpoint URL and signing secret in the app.
- Subscribe to
document.completedfirst; add failure events when your support process is ready. - Return a
2xxquickly after storing the delivery. - Run downstream mapping asynchronously.
Never start payment, posting, or approval automation before signature verification and idempotency storage have both succeeded.
Map invoice fields into an ERP
For invoice capture, start with a small stable mapping and keep candidates available for review. Do not require every optional field before creating a draft posting.
| ERP field | exdata field | Mapping note |
|---|---|---|
| Supplier | sender_name, sender_vat_number | Use identifiers for matching when names vary. |
| Invoice number | document_number | Combine with supplier and issue date for duplicate checks. |
| Invoice date | issue_date | Fallback to date only if your process allows it. |
| Due date | payment_due_date | Keep nullable for invoices without explicit terms. |
| Total | gross_amount, currency | Amounts are strings; convert with decimal-safe code. |
| Tax lines | tax_breakdowns | Use row-level taxability and collection mechanism for tax codes. |
| Payment details | iban, bic, payment_reference | Require review before first payment to a new account. |
Handle failed and blocked documents
A terminal state is not always successful. Treat error and blocked as explicit workflow states so your team can resolve the document instead of losing it in a retry loop.
| Status | Inspect | Recommended action |
|---|---|---|
error | processing_error, latest extraction run error fields, credits_charged | Show manual review or retry after the file/source problem is understood. A terminal or preprocessing error returns all applied credits and reports zero only when neither a usable result nor retrievable extracted fields remain. |
blocked | blocked_reason, credits_charged | Resolve the reported account condition before re-uploading. page_band_insufficient_credits can arrive after 201 and returns the initial credits. |
pending too long | processing_stage, X-Request-ID | Keep polling with backoff and provide a support path. |
Reprocessing a document after an already charged usable result does not create a second charge. Its extraction run reports credits_charged: 0; the original charged run remains the billable result. If a failed run was fully returned, later reprocessing receives a new page-band charge only when it first leaves a usable result or retrievable extracted fields.
Custom document types
exdata has standard document types such as invoice, credit-note, bank-statement, contract, timesheet, letter, and other. Use custom_types[] to extend those categories for your workflow, not to replace the normalized type field.
curl -sS -X POST "https://www.exdata.app/api/v1/documents" \
-H "Authorization: Bearer $EXDATA_API_TOKEN" \
-H "Idempotency-Key: supplier-onboarding-2026-1048" \
-F "file=@./supplier-form.pdf" \
-F "custom_types[]=supplier-onboarding" \
-F "custom_types[]=invoice"