Skip to the content

Extractions

Send a document, choose a mode, and read every part of the result.

On this page

An extraction reads one document with one document type and returns its values, each with the evidence for it. It is created by POST /v1/extractions and has an id that starts rv_req_, which is also the request's id.

Send a document#

The request is multipart/form-data. It needs documents.extract, and documents.upload when it carries a file.

RECEVIZ_API="https://accounthouse-backend-793493499887.me-central1.run.app/api/receviz/v1"

curl "$RECEVIZ_API/extractions" \
  -H "Authorization: Bearer $RECEVIZ_SECRET_KEY" \
  -F "file=@receipt.jpg" \
  -F "document_type=payment_receipt" \
  -F "mode=standard"
filefile

The document: JPEG, PNG, WebP, TIFF, HEIC/HEIF or PDF. Its type is decided by its bytes, never by its name or declared content type. Optional when client_ocr is sent.

document_typestring

The document type's key, such as payment_receipt. Optional only when the application has a default document type.

schema_versioninteger

A published version to use. By default, the application's pinned version or the latest.

modestring

fast, standard or verified. By default, the application's default mode, or standard.

asyncboolean

true to process in the background and answer 202 at once. The default is false.

optionsJSON object, as a string

See Options below.

metadataJSON object, as a string

Your own keys, returned on the extraction and in its webhooks: a flat object of strings, numbers, booleans or null, at most 2048 bytes. Only the first 50 keys are kept, and longer names and texts are cut to 40 and 500 characters. Use it for your ids, not for document content.

client_ocrJSON object, as a string

Text read on the device, instead of or as well as the file. See Device text.

Headers:

AuthorizationBearerrequired

A secret key, or a client token in an app or a page.

Idempotency-Keystring

Makes a retry safe. See Retry safely.

X-ReceViz-SDKstring

Which SDK sent the request, as platform/version (web/0.1.0). The SDKs set it; it is shown in your request log.

Wait for it, or come back for it#

A small document is read while you wait and answered with 200 and the full result. A request with async=true is queued and answered at once with 202, the extraction's id, status queued and a Location header pointing at it.

Large documents are queued even when you asked to wait: a file over 10 MB, or a PDF of more than three pages. The 202 response then has no warnings list, but the finished result carries the warning processed_async.

json
{
  "id": "rv_req_8fK2aQ0zT3mN1pL5vB7xY9",
  "object": "extraction",
  "status": "queued",
  "livemode": false,
  "application": "app_Q3fK8sLm2VxT9pNa4RwZ1c",
  "document_type": "invoice",
  "schema_version": 3,
  "mode": "standard",
  "created_at": "2026-09-27T09:14:05Z",
  "completed_at": null,
  "metadata": {}
}

Collect the result with GET /v1/extractions/{extraction_id} until its status is succeeded or failed, or subscribe to the extraction.completed and extraction.failed webhooks. The SDKs poll for you, starting at one second and backing off to eight.

RECEVIZ_API="https://accounthouse-backend-793493499887.me-central1.run.app/api/receviz/v1"

# 202 Accepted: the body has the extraction's id and status "queued",
# and the Location header points at it.
curl -i "$RECEVIZ_API/extractions" \
  -H "Authorization: Bearer $RECEVIZ_SECRET_KEY" \
  -H "Idempotency-Key: invoice-2026-09-000731" \
  -F "file=@statement.pdf" \
  -F "document_type=invoice" \
  -F "async=true"

# Then fetch it until status is "succeeded" or "failed".
curl "$RECEVIZ_API/extractions/rv_req_8fK2aQ0zT3mN1pL5vB7xY9" \
  -H "Authorization: Bearer $RECEVIZ_SECRET_KEY"
  • A request that waits has 90 seconds to be read. When reading takes longer, the answer is 504 processing_timeout: send that document with async=true.
  • A queued document has ten minutes. An extraction left stuck is picked up again, up to three attempts, and then fails with processing_timeout.
  • The file of a queued document is held in private storage only until it is processed, and deleted as soon as the extraction succeeds or fails.

Retry safely#

Send an Idempotency-Key header (up to 128 characters, such as a UUID or your own order id) and a retry of the same request within 24 hours returns the first extraction instead of making a second one. The replayed response carries Idempotent-Replayed: true, and is 200 if the first extraction has finished or 202 if it is still running.

“The same request” means the same file bytes, document_type, schema_version, mode and options, and whether client_ocr was sent. Reusing a key for anything else within the 24 hours answers 409 idempotency_key_reused. Keys are remembered per credential; a client token shares its key's.

Modes#

The three modes are profiles over the same stages, not different engines.

Processing modes
ModeWhat runsWhen to use it
fastOCR and deterministic extraction. Values are typed and field thresholds apply, but no validation, no document rules, no arithmetic verdict and no language model: validation.performed is false.The quickest answer, when you check the values yourself
standardEverything in FAST, plus field validation, the document type's rules, the document's own arithmetic, confidence thresholds and review. This is the default.Most integrations
verifiedEverything in STANDARD, plus a language model as a second reader for exactly the fields that are uncertain, grounded in the document's own lines.When a wrong value costs more than a slower answer

VERIFIED mode needs the documents.verify capability and a data policy that allows language models; otherwise it is refused (403 missing_capability or 403 verification_disabled) rather than quietly run as STANDARD. See Confidence and verification for what the second reader may and may not do.

Options#

options is a JSON object sent as one form field, for example options={"include_ocr":"text","reference_date":"2026-09-27"}. An application can set defaults for some of them in the console; a request overrides those, except that evidence can only be made stricter.

include_ocrnone | text | lines

Return the recognised text as well: text needs ocr.basic, lines (every line with its box and confidence) needs ocr.structured. When the evidence level is none, the text is withheld and the warning ocr_output_withheld says so. Default none.

evidencefull | boxes_only | none

How much of the document travels back with each value. It can only tighten the level set by the data policy and the application. See Evidence levels.

tilingauto | off | force

Adaptive Document Tiling. force needs adaptive_tiling; without that capability, tiling is off. Default auto.

date_orderDMY | MDY

How to read 03/04/2026. By default, the application's setting, then the document type's, which is DMY unless set otherwise.

reference_dateYYYY-MM-DD

The day to treat as today, for not_future, max_age_days and judging whether a date is plausible. By default, the current date (UTC).

known_merchantsarray of strings

Merchant names you already know: up to 250 names of up to 60 characters. A printed name close to one of them (a garbled logo, a missing letter) is read as that name. The list is only matched against what is printed: it never puts a merchant on a document that does not show one.

default_currencystring

A three-letter currency code to assume when the document prints none. A field with the currency semantic that was not found gets this value, marked as not read: status default, source default, confidence 0. By default, the application's setting, then the document type's.

ocr_providerauto | document_ai | gemini | client

Which recogniser reads the document. Leave it at auto, which prefers the document OCR service and falls back to model transcription where the data policy allows it.

Device text#

An app that already read the document on the device can send that text as client_ocr: one page as {"width", "height", "lines": [{"text", "x", "y", "w", "h", "confidence"}]}, or several as {"pages": [...]}. Coordinates are fractions of the page from 0 to 1, with the origin at the top-left; confidence is optional. Up to 2,500 lines a page and 30 pages.

RECEVIZ_API="https://accounthouse-backend-793493499887.me-central1.run.app/api/receviz/v1"

curl "$RECEVIZ_API/extractions" \
  -H "Authorization: Bearer $RECEVIZ_SECRET_KEY" \
  -F "document_type=payment_receipt" \
  -F 'client_ocr={"width": 800, "height": 880, "lines": [ {"text": "DATE: 26/09/2026", "x": 0.05, "y": 0.3136, "w": 0.4, "h": 0.0409}, {"text": "AED 150.00", "x": 0.65, "y": 0.7136, "w": 0.3, "h": 0.05} ]}'
  • FAST and STANDARD read the device's text and never call a cloud recogniser; processing.ocr_provider is client.
  • VERIFIED still reads the image when one is sent, because a verifier that sees only the device's reading would be checking the device against itself.
  • Without a file, the request needs documents.extract but not documents.upload.

The response#

A finished extraction. This one was made from the receipt on the ReceViz home page, sent as device text, so no cloud recogniser ran and there is no picture to measure:

json
{
  "id": "rv_req_8fK2aQ0zT3mN1pL5vB7xY9",
  "object": "extraction",
  "status": "succeeded",
  "livemode": false,
  "application": "app_Q3fK8sLm2VxT9pNa4RwZ1c",
  "document_type": "payment_receipt",
  "schema_version": 1,
  "schema_id": "sch_7HdK2mQpX9sLw4VbN8cT1e",
  "mode": "standard",
  "created_at": "2026-09-27T09:14:05Z",
  "completed_at": "2026-09-27T09:14:06Z",
  "data": {
    "amount": 150,
    "currency": "AED",
    "transaction_date": "2026-09-26",
    "transaction_time": "14:05",
    "receipt_number": "000102",
    "rrn": "626914123456",
    "auth_code": "A1B2C3",
    "terminal_id": "12345678",
    "payment_method": "card",
    "card_scheme": "visa",
    "card_last_four": "4242",
    "approved": true,
    "merchant": "BLUE DHOW CAFE",
    "merchant_address": "DUBAI MARINA WALK"
  },
  "fields": {
    "amount": {
      "value": 150,
      "type": "currency",
      "status": "ok",
      "confidence": 0.906,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.77,
        "y": 0.7136,
        "width": 0.18,
        "height": 0.05
      },
      "raw_text": "AED 150.00"
    },
    "currency": {
      "value": "AED",
      "type": "string",
      "status": "ok",
      "confidence": 0.941,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": null,
      "raw_text": null
    },
    "transaction_date": {
      "value": "2026-09-26",
      "type": "date",
      "status": "ok",
      "confidence": 0.935,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.2,
        "y": 0.3136,
        "width": 0.25,
        "height": 0.0409
      },
      "raw_text": "DATE: 26/09/2026"
    },
    "transaction_time": {
      "value": "14:05",
      "type": "string",
      "status": "ok",
      "confidence": 0.941,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.825,
        "y": 0.3136,
        "width": 0.125,
        "height": 0.0409
      },
      "raw_text": "TIME: 14:05"
    },
    "receipt_number": {
      "value": "000102",
      "type": "string",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.8,
        "y": 0.3773,
        "width": 0.15,
        "height": 0.0409
      },
      "raw_text": "INVOICE NO: 000102"
    },
    "rrn": {
      "value": "626914123456",
      "type": "string",
      "status": "ok",
      "confidence": 0.941,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.175,
        "y": 0.4409,
        "width": 0.3,
        "height": 0.0409
      },
      "raw_text": "RRN: 626914123456"
    },
    "auth_code": {
      "value": "A1B2C3",
      "type": "string",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.325,
        "y": 0.5046,
        "width": 0.15,
        "height": 0.0409
      },
      "raw_text": "AUTH CODE: A1B2C3"
    },
    "terminal_id": {
      "value": "12345678",
      "type": "string",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.175,
        "y": 0.25,
        "width": 0.2,
        "height": 0.0409
      },
      "raw_text": "TID: 12345678"
    },
    "payment_method": {
      "value": "card",
      "type": "enum",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": null,
      "raw_text": null
    },
    "card_scheme": {
      "value": "visa",
      "type": "enum",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.05,
        "y": 0.5682,
        "width": 0.1,
        "height": 0.0409
      },
      "raw_text": "VISA"
    },
    "card_last_four": {
      "value": "4242",
      "type": "string",
      "status": "ok",
      "confidence": 0.941,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.85,
        "y": 0.5682,
        "width": 0.1,
        "height": 0.0409
      },
      "raw_text": "************4242"
    },
    "approved": {
      "value": true,
      "type": "boolean",
      "status": "ok",
      "confidence": 0.931,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.4,
        "y": 0.8,
        "width": 0.2,
        "height": 0.0409
      },
      "raw_text": "APPROVED"
    },
    "merchant": {
      "value": "BLUE DHOW CAFE",
      "type": "string",
      "status": "ok",
      "confidence": 0.912,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.29,
        "y": 0.0818,
        "width": 0.42,
        "height": 0.05
      },
      "raw_text": "BLUE DHOW CAFE"
    },
    "merchant_address": {
      "value": "DUBAI MARINA WALK",
      "type": "string",
      "status": "ok",
      "confidence": 0.865,
      "verified": false,
      "checks": [],
      "source": "rules",
      "page": 1,
      "bounding_box": {
        "x": 0.2875,
        "y": 0.15,
        "width": 0.425,
        "height": 0.0409
      },
      "raw_text": "DUBAI MARINA WALK"
    }
  },
  "review": {
    "required": false,
    "reasons": []
  },
  "validation": {
    "performed": true,
    "rules": [],
    "arithmetic": {
      "status": "unknown",
      "amount": "150.0"
    }
  },
  "verification": {
    "performed": false
  },
  "warnings": [],
  "quality": {
    "score": null,
    "issues": [],
    "pages": []
  },
  "enrichment": {
    "merchant": null
  },
  "processing": {
    "engine": "receviz-engine/1.0.0",
    "mode": "standard",
    "ocr_provider": "client",
    "pages": 1,
    "tiling": {
      "applied": false,
      "pages": {}
    },
    "timings_ms": {
      "quality": 0,
      "ocr": 0,
      "layout": 0,
      "extraction": 1,
      "validation": 0,
      "verification": 0,
      "total": 2
    },
    "source": "api"
  },
  "metadata": {
    "order": "A-17"
  }
}
idstring

rv_req_…. The same id is the request id in X-Request-Id, in the request log and in webhooks.

statusstring

queued, processing, succeeded or failed.

livemodeboolean

True for live keys.

document_type, schema_version, schema_idstring, integer, string

Exactly which published version read the document.

modestring

The mode that ran.

dataobject

The values alone, shaped like the document type; every field present, null when not found.

fieldsobject

Each value with its evidence. See below.

reviewobject

required, and the reasons a person should look.

validation, verificationobject

What was checked, and what the second reader did.

warningsarray

Things about the request or the document worth knowing.

qualityobject

How good the picture was.

enrichmentobject

What ReceViz adds from its own knowledge rather than from the page, such as the known brand.

processingobject

How the document was read, and how long each stage took.

ocrobject

Only with options.include_ocr.

metadataobject

Yours, as sent.

Fields: each value with its evidence#

fields has one entry per field of the document type. A scalar field looks like fields.amount above:

valueany

The typed value, the same as in data. Null when not found.

typestring

The field's type from the definition.

statusstring

ok, missing, invalid (it broke a validation check), needs_review (below its threshold, a rule failed, the arithmetic does not add up, or the verifier disagreed) or default (its fallback value).

confidencenumber or null

From 0 to 1; null when there is no value.

verified, checksboolean, array

checks lists what independently backed the value: arithmetic (the document's own sums) and verifier (the second reader agreed, or found it). verified is true when there is at least one.

sourcestring

What produced the value: rules (tuned rules), label, type, pattern, verifier, inferred, default or none.

pageinteger

Which page it was printed on, counting from 1.

bounding_boxobject

Where it was printed, as {x, y, width, height} in fractions of the page from the top-left corner. Null for a value that is not printed in one place, such as a currency taken from a price.

raw_textstring

The printed line or lines the value came from.

issuesarray

{code, message, severity}: for example pattern_mismatch, ambiguous or rule_failed. Severity is warning or error.

verificationobject

In VERIFIED mode, what the second reader concluded about this field, and why.

alternativesarray

Other values the document supported, each with its score, best first: what a person would choose between when reviewing.

An object field is {"type": "object", "status", "confidence", "fields": {…}} with a result per sub-field. An array field is {"type": "array", "status", "confidence", "items": [{…}]}, one object of field results per item; its status is ok, empty, or missing when it is required.

Evidence levels#

The evidence level decides how much of the document comes back. It is set by the data policy, can be made stricter by the application, and stricter again by a request.

Evidence levels
LevelEach value comes with
fullPage, bounding box, printed text and alternatives; the verifier's alternative value; the arithmetic's figures
boxes_onlyPage and bounding box, but no printed text
noneValues, statuses, confidences and checks only

The same amount, under boxes_only and then none:

json
{
  "value": 150,
  "type": "currency",
  "status": "ok",
  "confidence": 0.906,
  "verified": false,
  "checks": [],
  "source": "rules",
  "page": 1,
  "bounding_box": {
    "x": 0.77,
    "y": 0.7136,
    "width": 0.18,
    "height": 0.05
  }
}

{
  "value": 150,
  "type": "currency",
  "status": "ok",
  "confidence": 0.906,
  "verified": false,
  "checks": [],
  "source": "rules"
}

Review#

review.required is true when a person should look before the values are used, and review.reasons lists why, each as {field, code, message}. Reasons about the document as a whole have a field of null.

Review reasons
CodeMeaning
missing_requiredA required field, or one whose fallback is error, was not found.
pattern_mismatch, below_minimum, date_in_future…The value broke one of its field's checks; the code is the first failed check.
low_confidenceThe confidence is below the field's threshold.
ambiguousAnother value on the document is almost as likely.
rule_failedA rule of the document type failed.
arithmetic_inconsistentThe document's own sums do not add up with this value.
verification_disagreedThe second reader read the field differently.

Accept automatically only what does not need review

A value can be well read and still wrong for your purpose. Store data directly when review.required is false; otherwise show the reasons, the printed text and the alternatives to a person.

Validation, verification, warnings, quality and processing#

validationobject

performed (false in FAST mode); rules, one entry per rule as {rule, type, status, fields, message} with status passed, failed or skipped; and arithmetic, whose status is consistent, inconsistent or unknown.

verificationobject

performed; how many fields needed it; when it did not run, a reason (nothing_uncertain, verifier_unavailable, verifier_failed); when it ran, the provider, the model, the time it took and the outcomes (agreed, disagreed, filled, rejected, unanswered).

warningsarray

{code, message}, such as processed_async, ocr_output_withheld, declared_type_mismatch (the file was not what its content type said; its bytes were used), no_text, document_contains_instructions, verification_unavailable, verification_failed, rule_failed and arithmetic_inconsistent.

qualityobject

Measured on each page before it is read: a score from 0 to 1, named issues (too_dark, overexposed, low_contrast, blurry, glare, low_resolution), and the brightness, contrast, sharpness and glare figures; per page in pages for a document of several. Quality never refuses a document: whether a poor photo still read is what the confidences say. The score is null when there was no picture.

processingobject

engine (the engine's version), mode, ocr_provider, pages, tiling (see Adaptive Document Tiling), timings_ms per stage (quality, ocr, layout, extraction, validation, verification and total) and source: api, sdk or playground.

ocrobject

With include_ocr=text: {text, pages, provider}. With lines: {provider, pages: [{page, width, height, lines: [{id, text, bounding_box, confidence}]}]}.

Known brands#

When the document type reads a merchant name, ReceViz checks it against the brands it knows: a few thousand merchants and banks, matched only when the match is certain. A wrong brand is worse than none, so an unknown shop gives merchant: null.

brandstring

The brand's stable key, such as carrefour.

namestring

The brand's own name. The printed name stays in data.

kindmerchant | bank

What kind of brand it is.

logo_urlstring | null

A 128 px WebP of the brand's logo, from GET /v1/brands/{brand}/logo, when logos are enabled for integrations; otherwise null. The link needs no key, and ReceViz does not log who loads it.

Other companies' trademarks

Brand names and logos belong to their owners. Show them only to identify the merchant on a document, never in a way that suggests the brand endorses your product. A logo can be withdrawn at any time; the link then answers 404, so fall back to the name.

Failed and purged extractions#

An asynchronous extraction that could not be processed has status failed and an error with the same codes as the API's errors. (A synchronous one answers with the error itself.)

json
{
  "id": "rv_req_8fK2aQ0zT3mN1pL5vB7xY9",
  "object": "extraction",
  "status": "failed",
  "livemode": false,
  "application": "app_Q3fK8sLm2VxT9pNa4RwZ1c",
  "document_type": "invoice",
  "schema_version": 3,
  "mode": "standard",
  "created_at": "2026-09-27T09:14:05Z",
  "completed_at": "2026-09-27T09:14:06Z",
  "metadata": {},
  "error": {
    "code": "pdf_encrypted",
    "message": "The PDF is password-protected. Send it without a password."
  }
}

Results are kept only as long as the data policy says. After that, the extraction still exists, but its values, evidence and metadata are gone:

json
{
  "id": "rv_req_8fK2aQ0zT3mN1pL5vB7xY9",
  "object": "extraction",
  "status": "succeeded",
  "livemode": false,
  "application": "app_Q3fK8sLm2VxT9pNa4RwZ1c",
  "document_type": "invoice",
  "schema_version": 3,
  "mode": "standard",
  "created_at": "2026-09-27T09:14:05Z",
  "completed_at": "2026-09-27T09:14:06Z",
  "metadata": {},
  "result_purged": true,
  "purged_at": "2026-09-28T09:14:06Z",
  "review_required": false,
  "message": "The result is no longer held: this application's data policy limits how long results are kept."
}

With the zero retention policy, a synchronous result is never stored, and an asynchronous one is handed over once, to the first fetch or webhook delivery, and then removed. See Data and privacy.

List recent extractions#

GET /v1/extractions lists the calling application's extractions, newest first, with metadata only and never a value: id, status, document type and version, mode, livemode, source, whether review was required, fields found and in total, pages, error code, total time, whether the result is still held, and when it was created and completed.

limit is 1 to 100 (default 25). To page back, pass the last id you have as starting_after; has_more says whether there are older ones.