Documents (OCR and UBL)
Send a purchase invoice or a receipt as a PDF, JPEG or PNG. AccountCloud reads it and gives you what is on it as JSON, in the line of EN 16931, and as UBL. A document is processed in one of two ways:
processing |
What happens | Ready |
|---|---|---|
automatic (default) |
Read by OCR. | Expected within 2 minutes. |
verified |
Read by OCR, then checked and corrected by a processor, who approves it only when its UBL passes the validation. | Within 24 working hours. |
OCR is not error-free. Check what you use, especially with automatic: the
warnings and the confidence help you decide which documents a person
should look at.
| Operation | Endpoint | Scope |
|---|---|---|
ocr.extract |
POST /v1/documents with processing: automatic |
ocr |
ubl.verified |
POST /v1/documents with processing: verified |
ubl |
ocr.read |
GET /v1/documents, GET /v1/documents/{id}, DELETE /v1/documents/{id} |
ocr |
ubl.generate |
GET /v1/documents/{id}/ubl |
ubl |
ocr.feedback |
POST /v1/documents/{id}/feedback |
ocr |
ubl.validate |
POST /v1/ubl/validate |
ubl |
A key needs the scope of the product, or the operation itself (see
scopes). A key that sends verified documents and reads
them back needs both, for example ubl and ocr.
Only sending a document costs money. Reading, listing and deleting documents, downloading the UBL,
validating a UBL file and reporting a wrong result are free. See what it costs.
All six operations are in preview: their status in GET /v1/pricing is
preview.
Send a document
Section titled “Send a document”As JSON, with the file in base64:
curl https://api.accountcloud.io/v1/documents \ -H "Authorization: Bearer ac_test_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 6f1c2e0a-4b7d-4e59-9a51-0c3f8f2d7b14" \ -d '{ "file": { "name": "invoice-2026-118.pdf", "content_base64": "JVBERi0xLjcK…" }, "processing": "automatic", "output": ["json", "ubl"], "own_party": { "name": "Example Bakery B.V.", "vat_number": "NL000000000B01", "country_code": "NL", "street": "Bakkerstraat", "house_number": "1", "postal_code": "1000 AA", "city": "Amsterdam" }, "reference": "inbox-48213", "metadata": { "administration": "8842" } }'Or as multipart, with the same fields as form fields:
curl https://api.accountcloud.io/v1/documents \ -H "Authorization: Bearer ac_test_…" \ -H "Idempotency-Key: 6f1c2e0a-4b7d-4e59-9a51-0c3f8f2d7b14" \ -F "processing=automatic" \ -F "output[]=json" -F "output[]=ubl" \ -F "own_party[name]=Example Bakery B.V." \ -F "own_party[vat_number]=NL000000000B01" \ -F "reference=inbox-48213" \ -F "metadata[administration]=8842"| Field | What it is |
|---|---|
file |
Required. In JSON an object with name (at most 255 characters) and content_base64, where a prefix such as data:application/pdf;base64, is allowed. In multipart a file field. At most 10 MB. The name only counts for test mode and display: the type is decided from the content. |
processing |
automatic (default) or verified. |
type |
A hint: purchase_invoice, receipt or auto (default). The OCR does not use it; with verified the processor sees it. |
direction |
purchase (default) or sales. On a purchase document own_party is the buyer, on a sales document the seller. |
output |
["json"] (default) or ["json", "ubl"]. With ubl the UBL is made and validated as soon as the document is completed; otherwise on the first download. |
country_hint |
A hint, ISO 3166-1 alpha-2. The OCR does not use it; with verified the processor sees it. |
own_party |
The party you process the document for: name, vat_number, registration_number, country_code, street, house_number, postal_code and city, all optional. It helps the OCR tell the supplier and the customer apart, and becomes the buyer (with sales, the seller) in the UBL. |
accepted_currencies |
Up to 20 ISO 4217 codes. With verified, a document in another currency is rejected with currency_not_accepted. |
reference |
Your own id for the document, at most 255 characters. The list can be filtered on it. |
metadata |
Up to 20 keys of 1 to 40 letters, digits, _, ., : or -, with text values of at most 500 characters. Comes back unchanged on the document and in every webhook. |
The answer is 202 Accepted, with the new document and its URL in Location:
HTTP/1.1 202 AcceptedLocation: /v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a{ "id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "object": "document", "status": "extracting", "processing": "automatic", "environment": "test", "reference": "inbox-48213", "metadata": { "administration": "8842" }, "file": { "name": "invoice-2026-118.pdf", "mime_type": "application/pdf", "size_bytes": 182311, "pages": 2, "sha256": "9f2c4e7a…" }, "duplicate_of": null, "expected_ready_at": "2026-11-04T09:16:12Z", "created_at": "2026-11-04T09:14:12Z", "extracted_at": null, "completed_at": null, "failure": null, "result": null, "confidence": null, "warnings": [], "verification": null, "rejection": null, "ubl": { "available": false, "href": "/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a/ubl", "valid": null, "profile": "peppol-bis-billing-3.0", "errors": [] }, "charge": { "operation": "ocr.extract", "status": "none", "amount": "0.0000", "currency": "EUR", "live_amount": "0.0350" }, "content_available": true, "content_purged_at": null, "retention_until": "2026-11-05T09:14:12Z"}This is a test document. With a live key a document starts as queued, its price is reserved
(charge.status: reserved), and retention_until is set once the document has its outcome.
expected_ready_at is the time of sending plus two minutes for automatic, and the deadline for
verified.
Checks at intake
Section titled “Checks at intake”The file is checked before anything is stored, with a test key too. A request that fails a check costs nothing.
- No file:
422file_missing. - Content that is not base64:
422invalid_base64. - More than 10 MB after decoding:
413file_too_large, withmax_bytes. - Not a PDF, JPEG or PNG, judged by the first bytes of the file:
415unsupported_media_type. The file name and a declared type do not count. - A PDF that asks for a password or cannot be opened:
422encrypted_pdf. More than 50 pages:422too_many_pages, withmax_pagesandpages. - An option with a value that is not allowed:
422invalid_option, with the option infield. Any other invalid field:422validation_failed. verifiedwhile it is switched off for your account:403verified_not_enabled. See also the daily maximum.
Duplicates and retries
Section titled “Duplicates and retries”The same file again. Within the same account, environment, entity and processing, the same
file gives 200 with the earlier document instead of a new one. Its duplicate_of is then set, to
that document’s own id. The answer costs nothing; the charge in it is still that of the earlier
document. It is not a duplicate when the earlier document failed, was deleted, or its content is
gone after the retention period, and neither is a file you sent as
automatic before and now send as verified. To have the same file read again, delete the earlier
document first. The SHA-256 of the file is in file.sha256.
Entities. When you send documents for several administrations or customers of your own, send
the AccountCloud-Entity header with your id for it (1 to 255 visible characters). Duplicates are
then found per entity, the list can be narrowed to it, and charges are recorded per entity.
Retrying a request. Send an Idempotency-Key with every POST. A retry with the same key and
the same request gets the first answer again, for 24 hours, with Idempotency-Replayed: true, and is
never charged twice. The same key with a different request (with multipart: a different file, too)
gets 409 idempotency_key_reused. Only a 2xx answer is
kept, so a retry after an error is processed anew. See idempotency.
Statuses
Section titled “Statuses”| Status | What it means |
|---|---|
queued |
Accepted, and waiting to be read. |
extracting |
Being read. When the OCR is busy or down, it is tried again after 2, 5, 15, 30 and 60 minutes, and the status stays extracting. |
awaiting_review |
Only verified: read, and waiting for a processor. |
in_review |
Only verified: a processor has it open. It goes back to awaiting_review when they let it go. |
completed |
Done. With verified: approved by a processor. |
failed |
Only automatic: the document could not be read. With failure.code. |
rejected |
Only verified: a processor rejected it. With rejection. |
completed, failed and rejected are final. The failure.code of a failed document:
| Code | Why |
|---|---|
extraction_failed |
The OCR failed in a way that trying again does not fix. |
document_unreadable |
The OCR could not read the file. |
provider_unavailable |
The OCR was still unavailable after the last retry. |
A failed document costs nothing, and you can send the file again. A verified document never fails:
when the OCR fails, it still goes to a processor, who fills it in by hand, and it gets the warning
extraction_failed.
Getting the result
Section titled “Getting the result”Webhooks
Section titled “Webhooks”Add a webhook endpoint in the portal (see webhooks) and pick the document.*
types:
| Type | When |
|---|---|
document.extracted |
Only verified: the document was read and waits for a processor. With expected_ready_at. |
document.completed |
The document is done. With verified: a processor approved it. |
document.failed |
Only automatic: the document could not be read. With failure. |
document.rejected |
Only verified: a processor rejected it. With rejection. |
The payload is thin: ids, the status, your reference and metadata, and the charge. Never the
contents of the document. Fetch the result with GET /v1/documents/{id}.
{ "type": "document.completed", "timestamp": "2026-11-04T09:14:16Z", "data": { "id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "status": "completed", "processing": "automatic", "reference": "inbox-48213", "metadata": { "administration": "8842" }, "charge": { "operation": "ocr.extract", "amount": "0.0350", "currency": "EUR" } }}charge is what the document costs at that moment; for a test document it also has
live_amount. A document’s events go to the endpoints of its environment: those of a test document
to your test endpoints.
Polling
Section titled “Polling”GET /v1/documents/{id} is free, but counts towards your
rate limits. expected_ready_at says when to expect the
outcome.
The document
Section titled “The document”curl https://api.accountcloud.io/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a \ -H "Authorization: Bearer ac_test_…"{ "id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "object": "document", "status": "completed", "processing": "automatic", "environment": "test", "reference": "inbox-48213", "metadata": { "administration": "8842" }, "file": { "name": "invoice-2026-118.pdf", "mime_type": "application/pdf", "size_bytes": 182311, "pages": 2, "sha256": "9f2c4e7a…" }, "duplicate_of": null, "expected_ready_at": "2026-11-04T09:16:12Z", "created_at": "2026-11-04T09:14:12Z", "extracted_at": "2026-11-04T09:14:15Z", "completed_at": "2026-11-04T09:14:15Z", "failure": null, "result": { "document_type": "invoice", "direction": "purchase", "invoice_number": "TEST-2026-0001", "issue_date": "2026-11-02", "due_date": "2026-12-02", "currency": "EUR", "order_reference": "PO-TEST-1", "customer_reference": null, "supplier": { "name": "Testleverancier B.V.", "vat_number": "NL000000000B02", "registration_number": "00000002", "iban": "NL91ABNA0417164300", "bic": null, "phone": null, "website": null, "address": { "street": "Leveranciersweg", "house_number": "2", "postal_code": "1000 AB", "city": "Amsterdam", "country_code": "NL" } }, "customer": { "name": "Testafnemer B.V.", "vat_number": "NL000000000B01", "matches_own_party": false }, "lines": [ { "description": "Advieswerk oktober", "quantity": "1", "unit_price": "100.00", "vat_rate": "21.00", "amount_excl_vat": "100.00", "verified": false }, { "description": "Vakboeken", "quantity": "2", "unit_price": "25.00", "vat_rate": "9.00", "amount_excl_vat": "50.00", "verified": false } ], "vat_breakdown": [ { "rate": "21.00", "taxable_amount": "100.00", "vat_amount": "21.00" }, { "rate": "9.00", "taxable_amount": "50.00", "vat_amount": "4.50" } ], "totals": { "amount_excl_vat": "150.00", "vat_amount": "25.50", "amount_incl_vat": "175.50" } }, "confidence": { "document": 0.95, "fields": { "invoice_number": 0.99, "issue_date": 0.99, "supplier.name": 0.98, "supplier.vat_number": 0.99, "totals.amount_incl_vat": 0.99, "totals.vat_amount": null } }, "warnings": [], "verification": null, "rejection": null, "ubl": { "available": true, "href": "/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a/ubl", "valid": true, "profile": "peppol-bis-billing-3.0", "errors": [] }, "charge": { "operation": "ocr.extract", "status": "none", "amount": "0.0000", "currency": "EUR", "live_amount": "0.0350" }, "content_available": true, "content_purged_at": null, "retention_until": "2026-11-05T09:14:12Z"}| Field | What it is |
|---|---|
status, processing, environment |
See statuses. environment is live or test. |
file |
name, mime_type (from the content), size_bytes, pages and sha256. |
duplicate_of |
Only set in the answer to a duplicate POST. |
expected_ready_at |
automatic: the time of sending plus two minutes. verified: the deadline. |
created_at, extracted_at, completed_at |
When the document was sent, read and completed. |
failure |
Only with failed: the code. |
result |
What was read; see below. null until the document is read, with verified until a processor approved it, and after the retention period. |
confidence |
See confidence. |
warnings |
See warnings. |
verification |
Only verified: whether a processor checked the document (verified, verified_at), and which fields they did not check (unverified_fields). |
rejection |
Only with rejected: the reason and a message. |
ubl |
available: whether the document is completed and its content still there; href: the download; valid and errors: the outcome of the validation, once the UBL was made; profile. See the UBL. |
charge |
See what it costs. |
content_available, content_purged_at, retention_until |
See retention. |
The result
Section titled “The result”Amounts are decimal strings in the currency of the document, with two decimals ("45.00"); rates
too ("21.00"). Any value can be null when it was not found.
| Field | What it is |
|---|---|
document_type |
What the document was read as: invoice, proforma, receipt, credit_note, quote, order, packing_slip, contract, bank_statement, reminder or other. |
direction |
purchase or sales, as you sent it. |
invoice_number, issue_date, due_date |
Dates in ISO 8601 (2026-11-02). |
currency |
ISO 4217. |
order_reference, customer_reference |
The order number and the customer number on the document. |
supplier |
name, vat_number, registration_number, iban, bic, email, phone, website, and the address (street, house_number, postal_code, city, country_code). |
customer |
name, vat_number, and matches_own_party: whether the customer on the document is the own_party you sent. |
lines |
description, quantity, unit_price, vat_rate, amount_excl_vat, and verified, which is always false: no processor checks the lines. |
vat_breakdown |
Per VAT rate: rate, taxable_amount and vat_amount. |
totals |
amount_excl_vat, vat_amount and amount_incl_vat. |
The field names are also the paths you use when you report a wrong result.
Confidence
Section titled “Confidence”confidence.fields has, per path of the result, how sure the OCR was of the text that value came
from, from 0 to 1. A value that was calculated or normalised rather than read from one place has
null. confidence.document is a rough score for the whole document: it mainly says whether the
amounts add up and the main fields were found on the page.
Neither number is calibrated: 0.95 does not mean that 95 out of 100 such values are right. Use them
to sort, for example to pick the documents a person looks at first, not as a probability. With
verified, confidence is that of the OCR, before the processor checked it.
Warnings
Section titled “Warnings”| Warning | What it means |
|---|---|
totals_do_not_reconcile |
The subtotal plus the VAT is not the total, the lines do not add up to the subtotal, or a VAT amount does not fit its rate and base. |
vat_breakdown_derived |
A taxable amount per rate was not on the document, and was calculated from its VAT amount. |
roles_swapped |
Supplier and customer look swapped: the document labels them the other way round, or on a sales document your own_party came out as the customer. |
multiple_documents_suspected |
The file seems to hold more than one invoice. A suspicion only: this cannot be detected reliably. |
text_truncated |
The document has more lines of text than were read. Check the lines and the totals. |
extraction_failed |
Only verified: the OCR failed, so the processor filled the document in by hand. |
GET /v1/documents/{id}?include=boxes adds boxes: where the values stand on the page, for example
to draw them over the PDF.
{ "boxes": { "header": [ { "key": "invoice_number", "value": "2026-000481", "confidence": 0.991, "page": 0, "vertices": [[0.61, 0.12], [0.74, 0.12], [0.74, 0.14], [0.61, 0.14]] } ], "lines": [ { "key": "title", "line_index": 0, "value": "Mobiele telefonie oktober", "confidence": 0.987, "page": 0, "vertices": [[0.08, 0.41], [0.36, 0.41], [0.36, 0.43], [0.08, 0.43]] } ] }}pagestarts at0.verticesare the four corners, as[x, y]from0to1of the width and height of the page, from the top left.keynames the value as the OCR found it: inheaderkeys such asinvoice_number,document_dateandtotal_amount, and keys starting withsupplier_,customer_,tax_andpayment_; inlineskeys such astitle,quantity,amount_eachandvat_percentage, with the position of the line inline_index. These keys are not the paths ofresult. A value can have more than one box, when it is on the page more than once.boxesis empty for a test document and after the retention period.
List documents
Section titled “List documents”curl "https://api.accountcloud.io/v1/documents?status=completed&limit=50" \ -H "Authorization: Bearer ac_test_…"{ "object": "list", "data": [ { "id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "object": "document", "status": "completed", "processing": "automatic", "reference": "inbox-48213", "metadata": { "administration": "8842" }, "file": { "name": "invoice-2026-118.pdf", "mime_type": "application/pdf", "size_bytes": 182311, "pages": 2, "sha256": "9f2c4e7a…" }, "failure": null, "rejection": null, "charge": { "operation": "ocr.extract", "status": "none", "amount": "0.0000", "currency": "EUR", "live_amount": "0.0350" }, "expected_ready_at": "2026-11-04T09:16:12Z", "created_at": "2026-11-04T09:14:12Z", "completed_at": "2026-11-04T09:14:15Z", "content_available": true } ], "has_more": false, "next_cursor": null}Newest first, without the result. Pass next_cursor as cursor for the next page. With an
AccountCloud-Entity header, only that entity’s documents.
| Parameter | What it does |
|---|---|
status |
Only documents with this status. |
processing |
automatic or verified. |
reference |
Only documents with this reference. |
created_after, created_before |
ISO 8601. From and including created_after, up to created_before. |
limit |
1 to 100; 25 by default. |
cursor |
The next_cursor of the previous page. |
The UBL
Section titled “The UBL”Download the UBL
Section titled “Download the UBL”curl https://api.accountcloud.io/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a/ubl \ -H "Authorization: Bearer ac_test_…" \ -o doc_01jbx6y4q9t2m8rz1v3k5n7p0a.xmlThe answer is UBL 2.1 according to Peppol BIS Billing 3.0, as application/xml. Every UBL we make is
validated; the outcome is on the document, in ubl.valid and ubl.errors. A UBL that does not pass
can still be downloaded.
- Before the document is
completed:409document_not_ready. The same code when no UBL could be made from the result at all;ubl.errorson the document then says why. - A rejected document has no UBL:
409document_rejected. - After the retention period:
410content_purged.
With automatic, the UBL is made from the result: when the document completes if you asked for
ubl in output, otherwise on the first download.
- On a purchase document the supplier is the seller and your
own_partythe buyer; on a sales document yourown_partyis the seller and the customer the buyer. Withoutown_partythe buyer only has the name and VAT number on the document, so the UBL usually does not pass the validation. Sendown_partywith its address when you need a valid UBL. - The lines of the result go into the UBL when they add up, per VAT rate and in total, to the VAT breakdown. Otherwise the UBL has one line per VAT rate.
- A 0% rate becomes “zero rated”, or “reverse charge” when the document says so. Intra-community supplies and exports are not assumed from the text of a document.
- A credit note becomes a UBL
CreditNote, with positive amounts. - The rates, amounts and totals are those of the result; nothing is recalculated, except where a breakdown is missing.
With verified, the UBL is made from the values the processor checked, with one line per VAT
rate, and the processor can only approve it when it passes the validation.
Validate a UBL file
Section titled “Validate a UBL file”POST /v1/ubl/validate checks a UBL 2.1 Invoice or CreditNote of yours against the UBL schema,
EN 16931 and Peppol BIS Billing 3.0. Send it as JSON with base64, or as multipart, at most 10 MB:
curl https://api.accountcloud.io/v1/ubl/validate \ -H "Authorization: Bearer ac_test_…" \{ "valid": false, "profile": "peppol-bis-billing-3.0", "complete": true, "engine": "saxon", "engine_error": null, "artifacts": { "ubl": "2.1", "peppol_bis": "3.0.20", "cen_schematron": "1.3.15" }, "errors": [ { "rule": "BR-CO-15", "level": "fatal", "location": "/Invoice", "message": "Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110)." } ]}- An invalid file is still a
200, withvalid: false.validistruewhen no finding isfatal. errorslists every finding,fatalandwarning: therule(such asBR-CO-15orPEPPOL-EN16931-R001;UBL-XSDfor the schema;UBL-XMLfor a file that is not well-formed XML, contains aDOCTYPE, or is not anInvoiceorCreditNote), itslevel, thelocationas an XPath, and the text of the rule.completeistruewhen the full official rule sets ran (engine: saxon). When it isfalse, only the schema and our own subset of the business rules ran (engine: php-subset), andvalidmeans “no rule we check is broken”, not “passes the official validator”.artifactshas the versions of UBL, Peppol BIS Billing and the EN 16931 schematron we validate against.- When the validator itself is down, the answer is
503service_unavailable.
As JSON, send {"file": {"content_base64": "…"}}; a name is optional.
Verified processing
Section titled “Verified processing”With processing: verified, a processor of our team checks and corrects what the OCR read, next to
the document. They can only approve it when all of this holds:
- the VAT breakdown adds up to the total, to the cent, and there is at least one VAT line;
- the supplier has a name, an IBAN passes its check digits, and a VAT number has the format of its country (it is not checked at VIES);
- there is an invoice number and a valid invoice date, and the due date is not before it;
- the currency is an ISO 4217 code, and one of your
accepted_currenciesif you sent them; - the UBL made from it passes the UBL schema, EN 16931 and Peppol BIS Billing 3.0.
The result of an approved document has the values the processor checked: the supplier, the header,
the VAT breakdown and the totals. Not checked:
- the lines.
verification.unverified_fieldsis["lines"], every line keepsverified: false, and the UBL has one line per VAT rate instead of the lines of the invoice; - the customer, which stays as the OCR read it. In the UBL of a purchase document, the buyer is
your
own_party, completed with what the OCR read.
The deadline
Section titled “The deadline”expected_ready_at is the deadline: 24 working hours after you sent the document. Working hours run
on Monday to Friday, Amsterdam time, and not on holidays: a document sent on Friday at 15:00 is due
on Monday at 15:00, one sent on Saturday on Tuesday at 00:00.
An account has a daily maximum of verified documents, 100 unless agreed otherwise. Above it, a
document gets the deadline of the next working day, and so on per block of that size, so
expected_ready_at shows the real expectation. At five times the maximum on one working day, a new
verified document gets 429 verified_daily_limit, with
daily_max.
Rejection
Section titled “Rejection”A processor can reject a document, with one of these reasons in rejection.reason, and their note
or a standard text in rejection.message:
| Reason | What it means |
|---|---|
not_readable |
The document could not be read. |
not_an_invoice |
The document is not an invoice or a receipt. |
multiple_documents |
The file holds more than one document. |
invoice_requirements |
The document does not meet the requirements of an invoice. |
duplicate |
This invoice was processed before: the same number from the same supplier. |
currency_not_accepted |
The currency is not one of your accepted_currencies. Only when you sent them. |
A rejected document has no UBL and no result. What a rejection costs is under
what it costs.
Retention and deleting
Section titled “Retention and deleting”We keep the content of a document (the file, the result and the UBL) for a limited time.
retention_until says until when.
- Live documents: until the retention period of your account after the outcome (
completed,failedorrejected). The period is 7 days unless an owner or admin sets 0 to 30 days in the portal. A change applies to documents that get their outcome after it. At 0 days the content is deleted right after the outcome, so there is hardly time to fetch the result. - Test documents: 24 hours after you sent them.
After that the document is still there, with content_available: false, content_purged_at, and no
result, confidence or file name. The UBL then answers 410
content_purged. The status, the times, the charge, your
reference and metadata, and the file’s type, size, pages and SHA-256 stay.
Delete a document to remove its content at once:
curl -X DELETE https://api.accountcloud.io/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a \ -H "Authorization: Bearer ac_test_…"{ "id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "object": "document", "deleted": true }After that, every call on the document answers 404
document_not_found. We keep its metadata (hash, pages,
cost, times and outcome) for our statistics. A verified document that is not done yet is taken off
the processors’ queue; it costs the OCR price when it was read already, otherwise nothing.
What it costs
Section titled “What it costs”A live document is charged once, at its outcome:
| Outcome | automatic |
verified |
|---|---|---|
Refused at intake (4xx), or a duplicate |
Free | Free |
completed |
The OCR price | The verified price |
failed |
Free | — |
rejected as a duplicate |
— | Free |
rejected for another reason, after the OCR read it |
— | The OCR price |
rejected, and the OCR could not read it |
— | Free |
| Deleted before the outcome | Free | The OCR price when the OCR read it, otherwise free |
The start prices are €0.0350 for the OCR (ocr.extract) and €0.3500 for verified
(ubl.verified), excluding VAT. The current ones are in GET /v1/pricing. A
document pays the price that applied when you sent it.
- When you send a live document, its full price is reserved on your credit. When the credit does not
cover it, the answer is
402insufficient_credits. - The
202itself hasAccountCloud-Charged: 0.0000: the price is taken at the outcome, and you find it inchargeon the document and in its webhook. charge.statusisreservedwhile the document is processed,capturedonce it is charged, andreleasedwhen its outcome costs nothing (operationis thennull). A test document hasnone, anamountof0.0000, and inlive_amountwhat it would cost live.
Report a wrong result
Section titled “Report a wrong result”When the OCR read a document wrong, tell us which fields:
curl https://api.accountcloud.io/v1/documents/doc_01jbx6y4q9t2m8rz1v3k5n7p0a/feedback \ -H "Authorization: Bearer ac_test_…" \ -H "Content-Type: application/json" \ -d '{ "result": "incorrect", "fields": [ { "field": "totals.vat_amount", "expected": "21.00" }, { "field": "supplier.vat_number", "expected": "NL000000000B02" } ], "comment": "The VAT amount was taken from the wrong line.", "allow_training": true }'{ "id": "fbk_01jbx6y4q9t2m8rz1v3k5n7p0b", "object": "feedback", "document_id": "doc_01jbx6y4q9t2m8rz1v3k5n7p0a", "training": "accepted"}| Field | What it is |
|---|---|
allow_training |
Required. true lets us add the document to the set we test and improve the OCR with. false keeps only the report, without the document. |
fields |
Up to 50 fields that were wrong. field is a path of the result, such as totals.vat_amount, supplier.address.city, or a line or VAT rate by its index: lines.1.amount_excl_vat, vat_breakdown.0.rate. expected is the value you expected, at most 500 characters. Another path gives 422 unknown_field. |
comment |
At most 2,000 characters. |
result |
Optional. Always incorrect. |
file |
Only needed after the retention period: the same file again, as content_base64. |
The answer is 202, and training says what we did:
accepted: the document joins the training set. We keep a copy of the file, what the OCR read and your report, for at most 12 months.stats_only: we keep only the report. That is the answer withallow_training: false, for every test document, and when your account has switched off sharing for training.
In the portal, an owner or admin can switch off sharing documents for training for the whole
account: a report with allow_training: true is then kept as a report only, and the answer says
stats_only. There they can also ask to delete every training case of the account.
After the retention period the original is gone, so a report needs the file again, in
file.content_base64. Its SHA-256 must be the file.sha256 of the document, or the answer is 422
file_hash_mismatch. Without the file it is 409
feedback_window_closed. A deleted document cannot be
reported on.
Reporting is free. An account can send 100 reports per UTC day unless agreed otherwise; after that
it gets 429 feedback_limit_reached until 00:00 UTC. A
report does not give back the price of the document by itself.
Test mode
Section titled “Test mode”With a test key, nothing is read and nothing is charged. A test document goes through the same
checks at intake, statuses and webhooks as a live one, and gets a fixed result that depends on its
file name: receipt.*, unbalanced.pdf, slow.pdf and fail.pdf for automatic, reject.pdf
and duplicate.pdf for verified. A verified test document is approved or rejected after a minute,
without a processor. The full list is in test mode.