For developers

API and webhooks

Run the same deterministic LC check from your own system: the same extraction, the same UCP 600 and ISBP 821 rules, the same result as in the browser. API access is part of the Enterprise plan.

What you can do

A deliberately small, versioned surface under /api/v1. A partner check goes through exactly the same extraction, redaction and rule engine as a check in the browser.

MethodPathScopeWhat it does
GET/api/v1/pingany active keyConfirms your key works. Returns the account email and plan. Spends no credit.
GET/api/v1/usageany active keyPlan, included checks per period, checks used this period, remaining check credits and period end. Spends no credit.
POST/api/v1/lc-checkslc:writeRuns a full LC Clear check on the documents you upload and returns the result. Billed exactly like a check in the browser.
GET/api/v1/lc-checks/{id}lc:readFetches a past result again. Only checks belonging to the key's own account.
POST/api/v1/lc-cases/{case_id}/document-checkslc:writeERP pre-check: checks the invoice (optionally with the bill of lading and the sales order) against the credit saved with one of your cases, without requiring the transport document. Billed like a check.
POST/api/v1/lc-reviewslc:writeReviews the credit itself before any document exists: the LC Workability Review (side=exporter) or the LC Pre-Issuance Review (side=importer). Spends no check credit.
GET/api/v1/lc-caseslc:readThe cases of your account, each with whether a credit is saved to it: how you find the case_id. Spends no credit.
GET/api/v1/finding-codesany active keyCatalogue of every explanation_code an LC Clear check can return, with its params, possible severities, the date it was added and, for a retired code, the date it was retired, plus the current rule set version. Spends no credit.

Authentication

The API authenticates with API keys, not a username and password, so your integration does not break when someone changes their password.

  • You create keys yourself under Settings in your DocAccord account (verified email address required).
  • Every request sends the key as a header: Authorization: Bearer da_live_.... Browser session logins are not accepted on /api/v1.
  • The key is shown exactly once. Only a SHA-256 hash and a short prefix for recognition are stored. A lost key is replaced, not recovered.
  • Scopes: lc:read fetches results, lc:write runs billable checks. New keys get both; you can narrow a key to one scope in Settings, for example for a system that only collects results.
  • Choose the lifetime: 30, 90, 180, 365 (default) or 730 days. Every new key expires. Up to 10 active keys per account. A revoked key stops working immediately. The owner and admins of the organisation see and revoke every key of the organisation.
  • Rotating without a gap: create the new key and name the one it replaces (replaces, optional overlap_hours from 1 to 72, default 24). The old key then expires after that period instead of being revoked at once.
  • The Enterprise plan is checked on every call, not only at creation. If an account leaves the Enterprise plan, its keys answer with 403.

Your first call

Start with ping. It resolves your key, runs no check and costs nothing.

curl
curl https://api.docaccord.com/api/v1/ping \
  -H "Authorization: Bearer da_live_YOUR_KEY"
Response 200
{
  "ok": true,
  "account_email": "trade-ops@example.com",
  "plan": "ENTERPRISE"
}

If the key is missing, unknown, revoked or expired, the API answers with 401.

Run a check

One multipart/form-data request with your documents. The response comes back synchronously once the check is stored.

  • Required: the credit and the commercial invoice. Each document either as a file (lc_file, invoice_file) or as text (lc_text, invoice_text), never both.
  • Transport documents, same pattern (_file or _text): bill_of_lading, multimodal_transport_doc, air_transport_doc, road_rail_inland_waterway_doc, charter_party_bill_of_lading, sea_waybill, courier_receipt. At least one is required unless field 46A of the credit asks for none; that is checked once the credit is read, before anything is billed.
  • Further transport sets (for example a second bill of lading, or an air waybill next to the bill of lading): up to three files in additional_transport_files, one set per file, with its type at the same position in additional_transport_types (such as BILL_OF_LADING, AIR_TRANSPORT_DOC). A check stays one credit.
  • Optional, same pattern: packing_list, weight_list, certificate_of_origin, insurance_certificate, bill_of_exchange, beneficiary_certificate, inspection_certificate. Plus the shipment advice as text in shipment_advice_text (a file variant follows once the size limit at the entry point is adjusted).
  • Files up to 20 MB: PDF, scans and photos (PNG, JPEG, GIF, WEBP, TIFF, BMP), DOCX, XLSX and text formats. The format is detected from the file content, not its name. The invoice may also be an EN 16931 e-invoice (XRechnung, ZUGFeRD, Factur-X, UBL or CII): as an XML file, or as a PDF with the XML attached. An XML file is read without AI (reading route E_INVOICE_XML in provenance); for a PDF with XML attached the pages are read and the XML then replaces the numbers, dates and ids. The bill of lading may also be an electronic bill of lading as a DCSA eBL 3.0 transport document (a JSON file, bill_of_lading_file or bill_of_lading_text): it is read from its data without AI (reading route EBL_DCSA_JSON) and counts as an electronic record where the credit is subject to eUCP. Only the data is read: the authenticity of the record, the platform and the title holder are not checked.
  • strictness: STANDARD (default) or STRICT.
  • amount_to_be_drawn (optional): the amount you claim under the credit, in its currency. When the invoice is above the credit, this amount decides (UCP 600 Art. 18(b)); without it and without a draft you get a warning to confirm.
  • presentation_date (optional, YYYY-MM-DD): the day you will present the documents. With it the API checks the presentation period (UCP 600 Art. 14(c)) and that no document is dated later (Art. 14(i)); without it a note (presentationDateNotGiven) says neither was checked.
  • instalment_number and earlier_instalments_on_time (optional): under a credit with an instalment schedule, which instalment you present (1 for the first) and whether every earlier instalment was shipped and drawn in its period (true or false). Without them the instalment is inferred from the shipment date (UCP 600 Art. 32).
  • presented_counts (optional): a JSON object with the originals and copies you present per document, for example {"insurance_certificate": {"originals": 1, "copies": 0}} (the keys are the document fields of the request). With it the check tells you when the credit or UCP 600 asks for more (Art. 17, Art. 19 to 22 and 28(b)); without it you keep the notes that the count cannot be verified. earlier_drawn_amount, earlier_drawn_quantity and earlier_containers_shipped (optional): what earlier drawings under this credit took, in its currency and unit. With them the API checks the credit as a whole (total amount, total quantity, the last containers; UCP 600 Art. 18(b), 30 and 31). An invalid value is a 400 before anything is read or billed.
  • presentation_medium (optional): PAPER, ELECTRONIC or MIXED, how the documents go to the bank, with MIXED plus electronic_doc_types (comma separated, for example INVOICE,PACKING_LIST). It matters only when the credit is subject to eUCP, which the API reads from fields 40E, 46A and 47A.
  • amendment_file or amendment_text (optional): one amendment (an MT707 or an amendment letter from the bank) you have not answered yet, with amendment_status PENDING, ACCEPTED or REJECTED (PENDING when left out). The documents are then checked against the credit as issued and the amended credit (UCP 600 Art. 10(c)); amendment_benchmark in the result says which one the findings are measured against. A status without an amendment is a 400.
  • If a required document is missing, the API answers with 400 before any document is processed or billed.
  • The credit is read first, then every other document at the same time, not one after the other. The response comes as soon as the slowest document has been read.
curl
curl -X POST https://api.docaccord.com/api/v1/lc-checks \
  -H "Authorization: Bearer da_live_YOUR_KEY" \
  -H "Idempotency-Key: shipment-4711-presentation-1" \
  -F "lc_file=@lc.pdf" \
  -F "invoice_file=@invoice.pdf" \
  -F "bill_of_lading_file=@bill_of_lading.pdf" \
  -F "packing_list_file=@packing_list.pdf" \
  -F "strictness=STANDARD"
Response 200 (abbreviated)
{
  "id": 1842,
  "report_number": "LCC-2026-001842",
  "lc_reference": "LC-2026-0457",
  "overall_status": "REJECTED_DISCREPANCIES",
  "compliance_score": 85,
  "findings": [
    {
      "rule_reference": "UCP 600 Art. 18(c) / ISBP 821 C3",
      "severity": "CRITICAL_ERROR",
      "affected_document": "Commercial Invoice #INV-2291",
      "field_name": "Goods Description",
      "found_value": "100% cotton men's shirts",
      "expected_value": "100% cotton men's shirts, style X",
      "explanation_code": "goodsDescExactMismatch",
      "explanation_params": {},
      "requires_acknowledgment": false,
      "suggested_fix_code": "goodsDescExactMismatchFix",
      "suggested_fix_params": { "lcText": "100% cotton men's shirts, style X" },
      "affected_doc_type": "INVOICE"
    }
  ],
  "created_at": "2026-09-23T09:14:02.118204"
}
  • overall_status is PASSED_FOR_BANK, WARNINGS_FOUND or REJECTED_DISCREPANCIES. severity is CRITICAL_ERROR, WARNING or INFO.
  • Each finding names the rule reference, the affected document and field, and the found and expected values. Instead of a rendered sentence the API returns a stable explanation_code with parameters, so you can render the text in your own system.
  • requires_acknowledgment is true when a person must confirm the finding because the data alone cannot decide it. suggested_fix_code with suggested_fix_params is the suggested correction, affected_doc_type the document type. The params of a published code never change; a new meaning gets a new code, and the old one stays in the GET /api/v1/finding-codes catalogue for 90 days.
  • provenance says what the check ran on: ruleset_version (the date of the rule set) and, per document, whether the DocAccord Reader read it (extraction_model, value docaccord-reader), whether an independent second reading ran (verify_model, value docaccord-reader), the reader version (prompt_sha) and the reading route (extraction_route). Both fields are empty when a document was typed rather than read. An old result stays explainable after the rules or the reader changed.
  • Use the id to fetch the result again later via GET /api/v1/lc-checks/{id}.

Retries without double billing

  • Optional header Idempotency-Key. If the same request is repeated with the same key, you get the stored result back: no second check, no second charge.
  • The same key with a different request returns 409. So does a second request while the first one with that key is still running.
  • For uploaded files, the request is recognised by the content of the file (SHA-256), not its name. Use a new key for every new document set.
  • Stored results are kept for at least 24 hours.

ERP pre-check

Check an invoice against the credit saved with a case at the moment your ERP creates it. Without the bill of lading, the packing list or the other documents: they come later. The result says what the bank would fault on this invoice before it leaves the house. The decision is the bank's.

  • The flow: a colleague reviews the credit in the DocAccord app and chooses Save credit terms to a case. Your ERP then calls POST /api/v1/lc-cases/{case_id}/document-checks for every invoice. Find the case_id with GET /api/v1/lc-cases (narrowed with lc_reference to the credit number).
  • The credit is not sent: the case's latest saved version is used. credit in the result names the case, the version and the save date it was checked against. Without a saved version (or while saving is switched off on the server) the API answers 409 with a note on what to do, before anything is read or billed. A case of another account and a case that does not exist are both 404.
  • The invoice is required (invoice_file or invoice_text, as on a check, including an EN 16931 e-invoice). Optional: the bill of lading (bill_of_lading_file or bill_of_lading_text, including a DCSA eBL 3.0 JSON) and the sales order (order confirmation, proforma invoice, sales contract or purchase order) as order_file or order_text, or as a JSON object in order_json that your ERP builds from its own data and that is compared with no reading. An order_json has at most 50,000 characters. Plus strictness, amount_to_be_drawn and presentation_date as on a check.
  • No transport document is required. Whatever else field 46A of the credit asks for counts as not yet presented and gives no "document missing" finding. Every other rule runs on what you sent. documents_checked names the documents that were checked; overall_status holds for those documents, not for a whole presentation.
  • The sales order is compared with the same saved credit (buyer, seller, goods, quantity, price, amount, currency, trade term, ports, delivery date, partial shipments, payment terms). order_check lists every difference as a warning with the wording you can ask the buyer's bank to amend, and what was not compared and why. It is not part of overall_status. A value the reading marked as unsure is not compared; an order_json counts as your own statement.
  • Billing, scopes, rate limit and Idempotency-Key are those of POST /api/v1/lc-checks: lc:write, one check credit per request once everything is read, 60 requests an hour per key. The documents are read at the same time. The run counts in your included checks and credits, but does not appear as a whole check in the app's history and gets no certificate. No webhook is sent.
  • The request size limit on this route is the API's general one (21 MiB per request, each file up to 20 MB).

Find the case_id

curl
curl "https://api.docaccord.com/api/v1/lc-cases?lc_reference=LC-2026-0457"   -H "Authorization: Bearer da_live_YOUR_KEY"
Response 200
{
  "storage_enabled": true,
  "cases": [
    {
      "id": 4711,
      "lc_reference": "LC-2026-0457",
      "lc_expiry_date": "2026-11-30",
      "latest_shipment_date": "2026-10-31",
      "credit": {
        "saved": true,
        "version": 2,
        "saved_at": "2026-09-24T08:12:44.101233",
        "source": "credit_review",
        "terms_available": true
      }
    }
  ]
}

Example SAP: billing document released

curl
# Sent by your SAP integration layer (SAP Integration Suite, or an ABAP class
# through an HTTP destination) when the billing document is released.
# 4711 is the DocAccord case id you stored on the sales order.
curl -X POST https://api.docaccord.com/api/v1/lc-cases/4711/document-checks   -H "Authorization: Bearer da_live_YOUR_KEY"   -H "Idempotency-Key: sap-billing-90001234"   -F "invoice_file=@90001234.pdf"   -F "order_json=<sales_order_5000123.json"
sales_order_5000123.json
{
  "document_kind": "OTHER",
  "order_number": "5000123",
  "order_date": "2026-08-14",
  "buyer": { "name": "Rotterdam AgriTrade B.V." },
  "seller": { "name": "Rhine Valley Commodities GmbH" },
  "currency": "EUR",
  "amount": 248000.00,
  "quantity": 49500,
  "quantity_unit": "MT",
  "stated_incoterm": "CIF",
  "incoterm_place": "Rotterdam",
  "delivery_date": "2026-09-05"
}
  • Field names of the standard A_SalesOrder OData service (check them against your own release): SalesOrder becomes order_number, SalesOrderDate becomes order_date, TransactionCurrency becomes currency, TotalNetAmount becomes amount, IncotermsClassification becomes stated_incoterm, IncotermsLocation1 becomes incoterm_place, RequestedDeliveryDate becomes delivery_date. The buyer's name comes from the business partner of SoldToParty, quantity and unit from the items (RequestedQuantity, RequestedQuantityISOUnit).
  • Leave a key out when your system does not know the value: it is not compared, and order_check.not_compared says so. Never send anything that is not on the order.

Example CargoWise: documents on the shipment

curl
# Sent by your integration when the commercial invoice and the bill of lading
# are attached to the shipment (for example through CargoWise's eAdaptor, or a
# workflow rule that calls your middleware). The bill of lading may be the PDF or
# a DCSA eBL 3.0 JSON record.
curl -X POST https://api.docaccord.com/api/v1/lc-cases/4711/document-checks   -H "Authorization: Bearer da_live_YOUR_KEY"   -H "Idempotency-Key: cargowise-S00012345-docs-1"   -F "invoice_file=@commercial_invoice.pdf"   -F "bill_of_lading_file=@ebl.json;type=application/json"   -F "presentation_date=2026-08-20"

Result

Response 200 (abbreviated)
{
  "id": 1843,
  "report_number": "LCP-2026-001843",
  "case_id": 4711,
  "lc_reference": "LC-2026-0457",
  "overall_status": "REJECTED_DISCREPANCIES",
  "documents_checked": ["INVOICE"],
  "credit": {
    "case_id": 4711,
    "case_reference": "LC-2026-0457",
    "version": 2,
    "saved_at": "2026-09-24T08:12:44.101233",
    "source": "credit_review"
  },
  "findings": [
    {
      "rule_reference": "UCP 600 Art. 18(c) / ISBP 821 C3",
      "severity": "CRITICAL_ERROR",
      "affected_document": "Commercial Invoice #INV-2291",
      "field_name": "Goods Description",
      "found_value": "100% cotton men's shirts",
      "expected_value": "100% cotton men's shirts, style X",
      "explanation_code": "goodsDescExactMismatch",
      "explanation_params": {},
      "requires_acknowledgment": false,
      "suggested_fix_code": "goodsDescExactMismatchFix",
      "suggested_fix_params": { "lcText": "100% cotton men's shirts, style X" },
      "affected_doc_type": "INVOICE"
    }
  ],
  "order_check": {
    "findings": [],
    "compared": ["buyer", "seller", "currency", "amount", "quantity", "incoterm", "delivery_date"],
    "not_compared": [{ "key": "unit_price", "reason": "not_on_order" }],
    "order_kind": "OTHER"
  },
  "created_at": "2026-09-29T09:14:02.118204"
}

The findings have the same shape as on a check (explanation_code with params, suggested_fix_code). The report number starts with LCP instead of LCC.

Credit review

Review the credit itself the moment it arrives or while it is still a draft, when an amendment is still a phone call. The exporter gets the LC Workability Review, the importer the LC Pre-Issuance Review: one route, two views.

  • The credit is required as lc_file (PDF, scan, photo) or lc_text (the pasted MT700 with its MT701s), never both. side is exporter (the default, the beneficiary's view, the LC Workability Review) or importer (the applicant's view, the LC Pre-Issuance Review). is_draft=true marks a draft the parties are still negotiating: the same checks run, but a finding is then a negotiating position rather than an amendment.
  • Optional: a sales order as order_file, order_text or order_json (the same keys as on the ERP pre-check). order_check lists every difference from the credit as a warning, apart from the status, counts and score.
  • Optional: case_id (one of your cases from GET /api/v1/lc-cases) or save_to_case=true saves the terms as a version with the source credit_review. Without a case_id the case is found or opened by the credit's reference number. The terms are saved only when every field the reading doubted was confirmed by a person. The API cannot do that, so for a reading with a doubt credit_saved.status is unconfirmed and nothing is saved. A draft is never saved (422). Without a save request the route saves nothing and credit_saved is null.
  • The response gives overall_status (WORKABLE, REVIEW_ADVISED or BLOCKED), risk_band and risk_score (our own weighted count, not a probability and not a rating by any bank), the findings with explanation_code, params and the severity for the other party, and advice and commercial, the commercial reading. The wording in suggested_clause is English because it goes into a credit. When it is locked for your account after the one free reveal, wording is null and locked is true; the finding itself is never withheld.
  • Billing: no check credit, as in the app. The reading goes through the same gate as POST /api/extract and the reading allowance for credits. A pasted MT700 is read too (the model reads it, a deterministic SWIFT reader reads the same text a second time and settles every difference); the review, the comparison with the order and the wording need no model. Scopes (lc:write), 60 requests an hour, the Idempotency-Key (its own scope) and the error format are those of POST /api/v1/lc-checks. The route is stateless: no id, no fetch route, no webhook. A retry with the same key returns the stored answer without reading again.
curl
# The LC Workability Review (side=exporter) of a credit that just arrived.
# Use side=importer for the LC Pre-Issuance Review of a draft you are about to
# send to your bank. lc_text takes the pasted MT700 instead of a file.
curl -X POST https://api.docaccord.com/api/v1/lc-reviews   -H "Authorization: Bearer da_live_YOUR_KEY"   -H "Idempotency-Key: credit-LC-2026-0457-review-1"   -F "lc_file=@lc.pdf"   -F "side=exporter"   -F "is_draft=false"
Response 200 (abbreviated)
{
  "lc_reference": "LC-2026-0457",
  "side": "exporter",
  "is_draft": false,
  "overall_status": "BLOCKED",
  "error_count": 1,
  "warning_count": 1,
  "risk_band": "MEDIUM",
  "risk_score": 33,
  "findings": [
    {
      "id": "IR-001",
      "rule_reference": "L/C Field 31D",
      "severity": "CRITICAL_ERROR",
      "field_name": "Expiry date (31D)",
      "explanation_code": "irAlreadyExpired",
      "explanation_params": { "expiry": "2026-09-01" },
      "requires_acknowledgment": false,
      "counterparty_severity": "CRITICAL_ERROR",
      "text_variant": null,
      "suggested_clause": null
    },
    {
      "id": "IR-003",
      "rule_reference": "UCP 600 Art. 28(g)",
      "severity": "INFO",
      "field_name": "Documents required (46A)",
      "explanation_code": "irInsuranceRisksUnstated",
      "explanation_params": { "document": "Insurance Certificate" },
      "requires_acknowledgment": false,
      "counterparty_severity": "INFO",
      "text_variant": null,
      "suggested_clause": {
        "clause_id": "LC-INS-02",
        "wording": "The insurance line in field 46A is amended to state the risks to be covered, ...",
        "locked": false,
        "rule_reference": "UCP 600 Art. 28(g)",
        "guidance_code": "clause.insuranceRisks"
      }
    }
  ],
  "advice": [
    { "code": "thirdPartyDocuments", "tone": "COST", "params": { "count": 2, "list": "Certificate of Origin; Insurance Certificate" }, "cost": 300.0, "cost_currency": "EUR" }
  ],
  "commercial": null,
  "order_check": null,
  "credit_saved": null,
  "ruleset_version": "2026-09-29",
  "created_at": "2026-10-01T09:14:02.118204+00:00"
}

Webhooks

Instead of polling for a finished check, your system receives a signed notification. Delivery runs after the API response is sent and never delays it.

  • check.completed: a check has been stored. data carries the same result as the POST /api/v1/lc-checks response. The ERP pre-check sends no webhook: its response is the result.
  • check.failed: a check could not be completed. data carries lc_reference and reason. Any check credit charged for it is refunded.
  • https URLs only, on a host that resolves to public internet addresses only (private, loopback and link-local addresses are refused, at registration and before every delivery). Up to 5 active endpoints per account, each subscribed to one or both events.
  • Endpoints are registered by a signed-in user of your account, not with an API key, so a leaked key cannot add new delivery targets.
  • On registration you receive a signing secret (whsec_...). It is shown once.
Delivery (abbreviated)
POST /your/webhook/path
Content-Type: application/json
X-DocAccord-Event: check.completed
X-DocAccord-Timestamp: 1790154842
X-DocAccord-Signature: sha256=5f0c1d...

{"event":"check.completed","data":{"id":1842,"report_number":"LCC-2026-001842",...}}

Verify the signature

  • Signature = HMAC-SHA256 with your secret over <timestamp>.<raw body>, sent as X-DocAccord-Signature: sha256=<hex> together with X-DocAccord-Timestamp and X-DocAccord-Event.
  • The timestamp is part of the signed material. Reject deliveries outside your own tolerance so a captured request cannot be replayed later.
  • Verify against the raw request body bytes before parsing JSON, and compare in constant time.
Python
import hashlib
import hmac
import time

TOLERANCE_SECONDS = 300

def verify(secret: str, headers: dict, raw_body: bytes) -> bool:
    timestamp = headers["X-DocAccord-Timestamp"]
    signature = headers["X-DocAccord-Signature"]
    if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS:
        return False
    signed = timestamp.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(
        secret.encode(), signed, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Delivery and retries

  • A response with a status below 300 counts as delivered. Timeout per attempt: 10 seconds.
  • On 5xx or network errors, up to 5 attempts with exponential backoff (1, 2, 4, 8 seconds). A 3xx or 4xx response is not retried, and redirects are not followed.
  • Every delivery is logged per endpoint: attempts, last status code, last error (for example timeout, connection failed or HTTP 503).
  • Webhooks are a notification, not a dependency. GET /api/v1/lc-checks/{id} stays the authoritative source if a delivery does not arrive.

Limits and billing

  • API access is included in the Enterprise plan. Other plans cannot create keys, and calls are refused with 403.
  • A check through the API is billed exactly like a check in the browser: first from the period's included checks, then from check credits.
  • When included checks and credits are used up, POST /api/v1/lc-checks answers with 402. GET /api/v1/usage shows where you stand at any time.
  • Enterprise accounts can buy check credit packs of any quantity on the Billing page and switch on automatic top-up: when the credit balance falls below a level you choose, the quantity you chose is bought and charged to your subscription's payment method (Paddle sends the invoice), up to a monthly limit you set. Credits arrive once Paddle confirms the payment, usually within a minute. A 402 while a top-up is running carries Retry-After, and GET /api/v1/usage shows auto_topup_enabled and topup_pending.
  • ping, usage, the list of cases, fetching past results and the credit review (POST /api/v1/lc-reviews) spend no check credit. An ERP pre-check (POST /api/v1/lc-cases/{case_id}/document-checks) spends one check credit once all its documents are read, exactly like a check; if reading fails it costs nothing.
  • Rate limit: 60 requests per hour per API key on POST /api/v1/lc-checks, POST /api/v1/lc-reviews and POST /api/v1/lc-cases/{case_id}/document-checks, 200 per hour per key on every other authenticated route. Above that the API answers with 429.
  • One check reads at most 15 documents, not counting the credit and its amendment. A request with more is refused with 429 before the first one is read; split the presentation into two checks. Documents of requests that fail after they were read count until a check completes, or for at most 24 hours after the first of those readings; a request whose documents no longer fit next to them gets 429 with Retry-After. Parallel requests do not count against each other.
  • Every API key has a daily limit for AI document reading that starts over at midnight UTC. At 80 percent the account's email address gets one warning a day; once the limit is reached the API answers 429 with Retry-After until midnight UTC. Close to the limit, a request can also get 429 with Retry-After 60 while other requests with the key are still running; retry it after a minute. Checks already running are not interrupted. Write to us if you need a higher limit.

Error codes

Errors come back as JSON with a human-readable detail field.

400Required document missing, file and text for the same document, or file not readable
401Key missing, unknown, revoked or expired
402Included checks and check credits used up
403Account not on the Enterprise plan, the key lacks the scope, or AI document reading is paused for the account (contact us)
404Check or case does not exist or does not belong to your account
409Idempotency-Key reused with a different request, or the first request is still running; on the ERP pre-check also: the case holds no saved credit (or saving credit terms is switched off on the server)
413File larger than 20 MB, more than 100 pages or more than 30 scanned pages, an image above 100 megapixels, pasted text above 1,000,000 characters, or a scan that took too long to process
422A field fails validation, a page (other than a photo or scan) is larger than A0, or the PDF is password protected
429Rate limit exceeded, or the key's daily limit for AI document reading reached (until midnight UTC; Retry-After says how long to wait), or more documents than one check reads (15, readings of failed requests included)
503Document reading is unavailable right now (an outage at the AI provider, or paused for a few minutes because of unusually high load); Retry-After says how long to wait

Environments

The prefix tells you at a glance which environment a key belongs to. A key only works in the environment that issued it.

EnvironmentBase URLKey prefix
Livehttps://api.docaccord.comda_live_
Sandboxhttps://api-staging.docaccord.comda_test_

Stability and schema

  • A breaking change to a v1 response is never made in place. It ships as /api/v2, and v1 keeps working.
  • If a v1 endpoint is retired, we give at least 90 days' notice: a Sunset header (RFC 8594) on that endpoint, and a direct notice to every partner whose active key used it in the preceding 30 days.
  • The partner API's OpenAPI schema is published at https://api.docaccord.com/api/v1/openapi.json, ready to import into Postman or any OpenAPI tool.

Put the check inside your own system

API access and webhooks are part of the Enterprise plan. Talk to us about your volume and your integration.