API documentation

Endpoint reference

Every document API endpoint with parameters, responses, fields, and copyable examples.

OpenAPI coverage

The operation list below is read from the published OpenAPI contract. Use it as a compact index when comparing generated clients, request methods, operation IDs, and documented response codes.

Method Path Operation Responses
GET /api/v1/ping Check API authentication ping 200
GET /api/v1/documents List documents listDocuments 200 429
POST /api/v1/documents Upload a document uploadDocument 201 422 409 429 402
POST /api/v1/x402/extractions Upload a document with x402 payment createAnonymousX402Extraction 200 201 400 402 409 422 429 503
GET /api/v1/x402/extractions/{document} Retrieve an anonymous x402 extraction getAnonymousX402Extraction 200 403 404 429
GET /api/v1/documents/{document} Retrieve a document getDocument 200 403 404
DELETE /api/v1/documents/{document} Delete a document deleteDocument 204 403 404
GET /api/v1/documents/{document}/thumbnail Download document thumbnail getDocumentThumbnail 200 403 404
GET /api/v1/documents/{document}/previews List document previews listDocumentPreviews 200 403 404
GET /api/v1/documents/{document}/extractions List document extractions listDocumentExtractions 200 403 404
GET /api/v1/previews/{preview} Download a preview file getPreview 200 403 404

Common headers

Each request is scoped to the account behind the API token. Upload retries should include an idempotency key so a network retry does not create another document.

Header Required Value Description
Authorization Yes Bearer <token> Account-scoped API token created in the exdata app. The token must have the ability required by the endpoint.
Idempotency-Key Uploads only String, max 255 characters Unique key for one logical upload. Reusing the same key and same payload returns the stored response.
X-Request-ID No String, max 128 characters Optional caller request ID. exdata echoes this value, or a generated request ID, in error responses.
GET /api/v1/ping

Ping

Use this endpoint for a lightweight token check during integration setup, deploy checks, or uptime probes that should not upload files.

ParameterLocationRequiredDescription
None-NoOnly the bearer token is required.
StatusResponseDescription
200JSON objectAuthentication succeeded.
401Error envelopeBearer token is missing, invalid, or revoked.
429Error envelopeRead rate limit exceeded.
Request
curl -sS "https://www.exdata.app/api/v1/ping" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN"
200 response
{
  "status": true
}
GET /api/v1/documents

List documents

Returns paginated documents for the token's account. Use this endpoint for status dashboards, reconciliation, support tooling, and scheduled backfills.

ParameterLocationRequiredTypeDescription
sortQueryNocreated_at or -created_atSort by creation time. Use -created_at for newest first.
per_pageQueryNoInteger, 1-100Number of documents per page. Defaults to 100.
StatusResponseDescription
200Paginated document listdata contains document objects. links and meta contain Laravel pagination data.
403Error envelopeThe token does not have documents:read.
422Validation errorA query parameter is not valid.
429Error envelopeRead rate limit exceeded.
Request
curl -sS "https://www.exdata.app/api/v1/documents?sort=-created_at&per_page=25" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN"
200 response
{
  "data": [
    {
      "id": 123,
      "mode": "live",
      "status": "completed",
      "processing_stage": "completed",
      "processing_error": null,
      "blocked_reason": null,
      "scanner_status": "clean",
      "scanner_provider": "local_noop",
      "scanner_message": null,
      "filename": "invoice-re-2026-1048.pdf",
      "file_format": "pdf",
      "file_size": 240123,
      "locale": "en",
      "custom_types": ["invoice"],
      "requester": "accounts-payable",
      "origin": "api",
      "ai_processing": true,
      "is_e_invoice": false,
      "thumbnail": "https://www.exdata.app/api/v1/documents/123/thumbnail",
      "previews": [
        {
          "id": 987,
          "filename": "page-1.png",
          "file_format": "png",
          "file_size": 94812,
          "preview": "https://www.exdata.app/api/v1/previews/987"
        }
      ],
      "latest_extraction_run": {
        "id": 456,
        "mode": "live",
        "source": "api",
        "status": "completed",
        "blocked_reason": null,
        "error_code": null,
        "error_message": null,
        "extraction_schema_version": "2026-05-17",
        "extractor_version": "document:2026-05-17",
        "ai_prompt_version": "document-ai:2026-05-17",
        "normalization_version": "base:2026-05-10",
        "started_at": "2026-05-10T01:00:04.000000Z",
        "completed_at": "2026-05-10T01:00:18.000000Z",
        "created_at": "2026-05-10T01:00:03.000000Z"
      },
      "created_at": "2026-05-10T01:00:00.000000Z",
      "updated_at": "2026-05-10T01:00:18.000000Z"
    }
  ],
  "links": {
    "first": "https://www.exdata.app/api/v1/documents?page=1",
    "last": "https://www.exdata.app/api/v1/documents?page=4",
    "prev": null,
    "next": "https://www.exdata.app/api/v1/documents?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 4,
    "per_page": 25,
    "to": 25,
    "total": 82
  }
}
POST /api/v1/documents

Upload document

Upload a file with multipart form data. The response is a document resource you can poll until processing is complete.

ParameterLocationRequiredTypeDescription
fileForm dataYesFile, max 500 MBDocument file. Supported file types are listed under Files and versioning.
textForm dataNoString or nullAdditional context you already know, such as the mailbox, source workflow, or customer note.
custom_types[]Form dataNoArray of stringsOptional type extensions for your workflow. Standard types are invoice, credit-note, reminder, salary-statement, bank-statement, contract, balance-sheet, tax-assessment-note, timesheet, letter, and other. Add custom values only when your integration needs extra document categories.
requesterForm dataNoString or nullIntegration name, user reference, workflow ID, or source system.
localeForm dataNoString or nullSupported locale such as en or de.
allow_ai_processingForm dataNoBooleanLegacy processing flag. Most integrations omit this field.
StatusResponseDescription
201Document resourceThe document was accepted. A pending extraction run is included when processing is queued.
402Insufficient credits errorThe document was created, then blocked because the account does not have enough credits.
403Error envelopeThe token does not have documents:write, or the account is suspended.
409Error envelopeThe idempotency key is still processing or was reused with a different upload payload.
422Validation errorThe file or form field failed validation.
429Error envelopeUpload rate limit exceeded, including sandbox daily upload limits for test-mode tokens.
Upload request with cURL
curl -sS -X POST "https://www.exdata.app/api/v1/documents" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN" \
  -H "Idempotency-Key: invoice-2026-1048" \
  -F "file=@./invoice-re-2026-1048.pdf" \
  -F "locale=en" \
  -F "custom_types[]=invoice" \
  -F "requester=accounts-payable"
201 response
{
  "data": {
    "id": 123,
    "mode": "live",
    "status": "pending",
    "processing_stage": "queued",
    "processing_error": null,
    "blocked_reason": null,
    "filename": "invoice-re-2026-1048.pdf",
    "file_format": "pdf",
    "file_size": 240123,
    "additional_text": null,
    "additional_text_plain": null,
    "custom_types": ["invoice"],
    "requester": "accounts-payable",
    "locale": "en",
    "number_of_pages": null,
    "origin": "api",
    "ai_processing": true,
    "is_e_invoice": false,
    "thumbnail": null,
    "previews": null,
    "extractions": null,
    "latest_extraction_run": {
      "id": 456,
      "mode": "live",
      "source": "api",
      "status": "pending",
      "blocked_reason": null,
      "error_code": null,
      "error_message": null,
      "extraction_schema_version": "2026-05-17",
      "extractor_version": "document:2026-05-17",
      "ai_prompt_version": "document-ai:2026-05-17",
      "normalization_version": "base:2026-05-10",
      "started_at": null,
      "completed_at": null,
      "created_at": "2026-05-10T01:00:03.000000Z"
    },
    "created_at": "2026-05-10T01:00:00.000000Z",
    "updated_at": "2026-05-10T01:00:03.000000Z"
  }
}
GET /api/v1/documents/{document}

Retrieve document

Fetch the current document status, file metadata, preview links, completed extraction fields, and the latest extraction run metadata.

ParameterLocationRequiredTypeDescription
documentPathYesIntegerDocument ID returned by create or list.
StatusResponseDescription
200Document resourceCurrent document state. Completed documents can include previews and extraction fields.
403Error envelopeThe token cannot access this document or lacks documents:read.
404Error envelopeNo document exists for this account and ID.
Request
curl -sS "https://www.exdata.app/api/v1/documents/123" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN"
200 response
{
  "data": {
    "id": 123,
    "mode": "live",
    "status": "completed",
    "processing_stage": "completed",
    "processing_error": null,
    "blocked_reason": null,
    "filename": "invoice-re-2026-1048.pdf",
    "file_format": "pdf",
    "file_size": 240123,
    "number_of_pages": 1,
    "origin": "api",
    "ai_processing": true,
    "is_e_invoice": false,
    "thumbnail": "https://www.exdata.app/api/v1/documents/123/thumbnail",
    "previews": [
      {
        "id": 987,
        "filename": "page-1.png",
        "file_format": "png",
        "file_size": 94812,
        "preview": "https://www.exdata.app/api/v1/previews/987"
      }
    ],
    "extractions": {
      "document_number": {
        "value": "RE-2026-1048",
        "candidates": ["RE-2026-1048"]
      },
      "gross_amount": {
        "value": "1079.50",
        "candidates": ["Total due EUR 1,079.50"]
      }
    },
    "latest_extraction_run": {
      "id": 456,
      "mode": "live",
      "source": "api",
      "status": "completed",
      "blocked_reason": null,
      "error_code": null,
      "error_message": null,
      "extraction_schema_version": "2026-05-17",
      "extractor_version": "document:2026-05-17",
      "ai_prompt_version": "document-ai:2026-05-17",
      "normalization_version": "base:2026-05-10",
      "started_at": "2026-05-10T01:00:04.000000Z",
      "completed_at": "2026-05-10T01:00:18.000000Z",
      "created_at": "2026-05-10T01:00:03.000000Z"
    },
    "created_at": "2026-05-10T01:00:00.000000Z",
    "updated_at": "2026-05-10T01:00:18.000000Z"
  }
}
DELETE /api/v1/documents/{document}

Delete document

Deletes the document resource for the account. Use this when your retention policy or customer request requires removal.

ParameterLocationRequiredTypeDescription
documentPathYesIntegerDocument ID to delete.
StatusResponseDescription
204 No ContentNo bodyDocument deleted.
403Error envelopeThe token cannot delete this document or lacks documents:write.
404Error envelopeNo document exists for this account and ID.
Request
curl -sS -X DELETE "https://www.exdata.app/api/v1/documents/123" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN" \
  -i
GET /api/v1/documents/{document}/thumbnail

Thumbnail

Downloads the generated thumbnail binary for a document when one is available.

ParameterLocationRequiredTypeDescription
documentPathYesIntegerDocument ID.
StatusResponseDescription
200Binary streamThumbnail file. The content type depends on the generated image.
403Error envelopeThe token cannot access this document or lacks documents:read.
404Error envelopeNo document or thumbnail exists for this account and ID.
Request
curl -L "https://www.exdata.app/api/v1/documents/123/thumbnail" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN" \
  -o document-123-thumbnail.png
GET /api/v1/documents/{document}/previews

List previews

Returns preview metadata for generated page or file previews. Use the returned preview ID with the preview download endpoint.

ParameterLocationRequiredTypeDescription
documentPathYesIntegerDocument ID.
StatusResponseDescription
200Preview listdata contains preview objects for this document.
403Error envelopeThe token cannot access this document or lacks documents:read.
404Error envelopeNo document exists for this account and ID.
Request
curl -sS "https://www.exdata.app/api/v1/documents/123/previews" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN"
200 response
{
  "data": [
    {
      "id": 987,
      "filename": "page-1.png",
      "file_format": "png",
      "file_size": 94812,
      "preview": "https://www.exdata.app/api/v1/previews/987"
    },
    {
      "id": 988,
      "filename": "page-2.png",
      "file_format": "png",
      "file_size": 88204,
      "preview": "https://www.exdata.app/api/v1/previews/988"
    }
  ]
}
GET /api/v1/previews/{preview}

Download preview

Downloads the binary preview file. Preview IDs are returned by the document previews endpoint and are account-scoped.

ParameterLocationRequiredTypeDescription
previewPathYesIntegerPreview ID returned by /documents/{document}/previews.
StatusResponseDescription
200Binary streamPreview file. The content type depends on the generated preview.
403Error envelopeThe token cannot access this preview or lacks documents:read.
404Error envelopeNo preview exists for this account and ID.
Request
curl -L "https://www.exdata.app/api/v1/previews/987" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN" \
  -o document-123-page-1.png
GET /api/v1/documents/{document}/extractions

Read extractions

Returns extracted fields keyed by field name. Call this after the document reaches completed or after receiving a document.completed webhook.

ParameterLocationRequiredTypeDescription
documentPathYesIntegerCompleted document ID.
StatusResponseDescription
200Extraction objectdata is an object keyed by normalized field name.
403Error envelopeThe token cannot access this document or lacks documents:read.
404Error envelopeNo document exists for this account and ID.
Read extractions with cURL
curl -sS "https://www.exdata.app/api/v1/documents/123/extractions" \
  -H "Authorization: Bearer $EXDATA_API_TOKEN"
200 response
{
  "data": {
    "type": {
      "value": "invoice",
      "candidates": ["Invoice"]
    },
    "document_number": {
      "value": "RE-2026-1048",
      "candidates": ["RE-2026-1048"]
    },
    "issue_date": {
      "value": "2026-05-10",
      "candidates": ["10 May 2026"]
    },
    "payment_due_date": {
      "value": "2026-06-09",
      "candidates": ["Due 09/06/2026"]
    },
    "sender_name": {
      "value": "Meyer Supply GmbH",
      "candidates": ["Meyer Supply GmbH"]
    },
    "recipient_name": {
      "value": "Northwind Operations Ltd.",
      "candidates": ["Northwind Operations Ltd."]
    },
    "currency": {
      "value": "EUR",
      "candidates": ["EUR"]
    },
    "net_amount": {
      "value": "1079.50",
      "candidates": ["Net amount EUR 1,079.50"]
    },
    "gross_amount": {
      "value": "1079.50",
      "candidates": ["Amount due EUR 1,079.50"]
    },
    "tax_breakdowns": {
      "value": [
        {
          "taxable_amount": "1079.50",
          "tax_amount": "0.00",
          "tax_rate": "0.00",
          "taxability": "taxable",
          "tax_collection_mechanism": "reverse_charge",
          "tax_exemption_reason": "Intra-EU B2B reverse charge"
        }
      ],
      "candidates": ["Reverse charge applies under Article 196 VAT Directive"]
    },
    "payment_reference": {
      "value": "RE-2026-1048",
      "candidates": ["Payment reference RE-2026-1048"]
    }
  }
}

Response objects

The tables below define the fields used by endpoint responses. The extraction field reference lists every normalized extraction key separately.

Document object

FieldTypeWhen presentDescription
idIntegerAlwaysDocument ID.
modelive or testAlwaysWhether the document was created by a live or test-mode token.
statuspending, completed, error, or blockedAlwaysCurrent document processing status.
processing_stageString or nullAlwaysCurrent stage such as queued, extracting, or completed.
processing_errorString or nullAlwaysHuman-readable processing failure message when status is error.
blocked_reasonString or nullAlwaysMachine-readable reason when status is blocked, for example insufficient_credits.
scanner_statusclean, rejected, or nullAlwaysUpload scanner decision when available.
scanner_providerString or nullAlwaysScanner provider or configured scanning backend.
scanner_messageString or nullAlwaysScanner explanation when available.
scanned_atDate-time or nullAlwaysWhen file scanning completed.
processing_started_atDate-time or nullAlwaysWhen processing work started.
processed_atDate-time or nullAlwaysWhen processing reached a terminal state.
filenameStringAlwaysOriginal uploaded filename.
file_formatStringAlwaysDetected or stored file extension, for example pdf.
file_sizeIntegerAlwaysFile size in bytes.
additional_textString or nullAlwaysOptional upload context supplied through the text form field.
additional_text_plainString or nullAlwaysPlain-text version of additional_text.
custom_typesArray of strings or nullAlwaysType extensions supplied at upload time.
requesterString or nullAlwaysCaller reference supplied at upload time.
localeString or nullAlwaysLocale hint supplied at upload time.
number_of_pagesInteger or nullAlwaysDetected page count when available.
extracted_textString or nullAlwaysExtracted document text when OCR/text extraction is available.
extracted_text_plainString or nullAlwaysPlain-text version of extracted_text.
originapi, app, or nullAlwaysWhere the document was created.
ai_processingBooleanAlwaysWhether extraction processing is enabled for this document.
is_e_invoiceBooleanAlwaysWhether the document was recognized as an e-invoice.
thumbnailURL or nullAlwaysDownload URL for the generated thumbnail.
previewsArray or nullAlwaysPreview objects for completed documents when previews are loaded.
extractionsObject or nullAlwaysExtraction fields for completed documents when extractions are loaded.
latest_extraction_runExtraction run or nullAlwaysLatest extraction attempt metadata.
created_atDate-timeAlwaysDocument creation timestamp.
updated_atDate-timeAlwaysLast document update timestamp.

Extraction run object

FieldTypeDescription
idIntegerExtraction run ID.
modelive or testBilling/reporting mode for the run.
sourceapi, app, or nullWhere the run was started.
statuspending, processing, completed, blocked, or errorRun status.
blocked_reasonString or nullMachine-readable block reason.
error_codeString or nullMachine-readable failure code.
error_messageString or nullFailure message for operators or support tooling.
extraction_schema_versionString or nullExtraction schema version used by this run.
extractor_versionString or nullExtractor implementation version.
ai_prompt_versionString or nullAI prompt version used by this run.
normalization_versionString or nullNormalization version used after extraction.
started_atDate-time or nullWhen extraction processing started.
completed_atDate-time or nullWhen extraction processing completed.
created_atDate-time or nullWhen the run record was created.

Preview object

FieldTypeDescription
idIntegerPreview ID used by the preview download endpoint.
filenameStringGenerated preview filename.
file_formatStringPreview file extension, for example png.
file_sizeIntegerPreview file size in bytes.
previewURLDownload URL for the preview binary.

Extraction field object

FieldTypeDescription
valueString, array, object, or nullNormalized value for system mapping. Amounts are dot-decimal strings, dates use YYYY-MM-DD, currency uses ISO 4217, and tax_breakdowns uses an array of tax rows.
candidatesArray or nullRaw or derived candidate values considered for the field. Use these in review UIs, support tools, and debugging.

Error envelope

FieldTypeDescription
messageStringHuman-readable error message.
codeStringMachine-readable error code such as validation_failed or insufficient_credits.
request_idStringRequest identifier for support and log correlation.
errorsObjectValidation field errors. Present on 422 responses.
retry_afterInteger or nullRetry delay in seconds. Present on some rate-limit responses.
available_creditsIntegerAvailable credits. Present on insufficient-credit upload responses.
required_creditsIntegerCredits required for the upload. Present on insufficient-credit upload responses.
documentDocument objectBlocked document created before credit reservation failed. Present on insufficient-credit upload responses.
account_daily_document_limitIntegerSandbox account daily upload limit. Present on test-mode limit responses.
user_daily_document_limitIntegerSandbox user daily upload limit. Present on test-mode limit responses.
token_daily_document_limitIntegerSandbox token daily upload limit. Present on test-mode limit responses.