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.

  1. Upload the file with POST /documents.
  2. Store data.id, data.mode, data.processing_lane, and your Idempotency-Key.
  3. Poll GET /documents/{document} until status is completed, error, or blocked.
  4. Read GET /documents/{document}/extractions when completed.
Polling decision
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.

Batch lane availability

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.

  1. Upload with processing_mode=thumbnail and a stable idempotency key.
  2. Store data.id and poll the document or wait for document.completed.
  3. Download GET /documents/{document}/thumbnail after completion.
  4. Treat document.failed or status: "error" as a thumbnail failure and inspect processing_error.
Thumbnail-only video upload
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 testExpected behaviorGo-live gate
Representative PDFsFields appear with useful candidates.Your mapper handles missing optional fields.
Duplicate upload retrySame idempotency key returns the stored response.Your integration can safely retry network failures.
Webhook receiverSignature verification and delivery dedupe pass.Your receiver stores processed delivery IDs.
Limit response429 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.

  1. Configure the endpoint URL and signing secret in the app.
  2. Subscribe to document.completed first; add failure events when your support process is ready.
  3. Return a 2xx quickly after storing the delivery.
  4. Run downstream mapping asynchronously.
Receiver rule

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 fieldexdata fieldMapping note
Suppliersender_name, sender_vat_numberUse identifiers for matching when names vary.
Invoice numberdocument_numberCombine with supplier and issue date for duplicate checks.
Invoice dateissue_dateFallback to date only if your process allows it.
Due datepayment_due_dateKeep nullable for invoices without explicit terms.
Totalgross_amount, currencyAmounts are strings; convert with decimal-safe code.
Tax linestax_breakdownsUse row-level taxability and collection mechanism for tax codes.
Payment detailsiban, bic, payment_referenceRequire 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.

StatusInspectRecommended action
errorprocessing_error, latest extraction run error fields, credits_chargedShow 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.
blockedblocked_reason, credits_chargedResolve the reported account condition before re-uploading. page_band_insufficient_credits can arrive after 201 and returns the initial credits.
pending too longprocessing_stage, X-Request-IDKeep 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.

Custom type extension
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"