Skip to main content
POST /v1/kyc/extract reads the files of one upload step and returns the fields it found, the checks that belong to each document, and, with a reference, a case id and document ids. Scope: kyc:extract. It is the only call that uses the vision model, so it is the only one that counts against your monthly read allowance.

Request

Multipart form (multipart/form-data). Only files is required. Send one document type per call. doc_type and step_key apply to all the files in the call, and a front and a back of the same card is the normal case for two files.

File rules

The content type comes from your multipart part header, not from the file name. Send the right Content-Type for each file part. Most HTTP libraries and curl -F set it from the extension.

What happens to a call

Order matters in two places. Validation errors (400, 413, 422) happen before the read is reserved, so they cost nothing. The reservation happens before the model runs, so a read that then fails still counts.

Response

The values above are fake. Which fields appear depends on the file you send.

Top-level keys

Keys of each documents[] entry

meta_provenance keys: for a PDF, producer and creator (the software, up to 200 characters), modified (the ModDate as YYYY-MM-DD, when it differs from the creation date), revisions (how many times the file was saved incrementally). For an image, creator (the EXIF Software tag) and camera (the EXIF Make tag). A missing EXIF block is not reported, because WhatsApp and most browsers strip it.

Field values

Every value in fields is a string. The reader is told to omit a field it cannot read, so a missing key means “not read”, never “empty”. The server then normalises: Corrections the server makes after the read, each listed in notes:
  • Bank details are kept only when the document is a bank document (void cheque, bank statement, bank letter, RIB). On any other document they are removed, because a utility bill’s account number or an invoice’s IBAN is not the client’s.
  • bank_number and bank_transit are Canadian codes. They are dropped when the document is from another country, or when the length is wrong (3 digits and 5 digits). A 9-digit bank_number is moved to bank_routing, since 9 digits is a US routing number.
  • A name that reads as a parent on a Moroccan card (... ben ..., fils de, bent) is dropped from first_name, last_name and document_holder_name.
  • On an invoice, the supplier’s legal name, address and registration numbers are not merged into fields unless the recipient is the same entity.
  • specimen_markings stays on the document entry and is never merged into fields.

Confidence

The API returns no per-field confidence and no per-document score. The reader gives values, not probabilities. Do not look for a confidence key. You can still judge a read: The console shows a fixed value of 0.9 for every field the reader returns. It is a label for “read by the model, not yet reviewed”, not a measurement, and field validation stays pending until a person reviews it.

reader_unavailable

reader_unavailable: true means at least one file was never read: no credentials on the Sahl side, a quota or timeout, or an answer that could not be parsed. It does not mean the document was blank. A blank or cropped document returns reader_unavailable: false and few or no fields. The call still returns 200. The read still counts. Retry the file later, and if it persists, quote the X-Request-ID header to Sahl. With a reference, each file is filed on the case with a status that you see in the console under Documents:

Document checks in the answer

Each file gets the checks that fit its type. They are the same checks /verify repeats on the entries you send back. The full list with meanings is in Verify a profile. In short: the document is the type the step expects (doctype:), its key fields were read (legible:), an ID is not expired (expiry:) or about to expire (expiry_soon:), the holder is 18 or older (adult:), a passport or ID card MRZ check digits are valid (mrz:), a proof of address is recent (recency:), the file was not re-saved from an editor (provenance:), and the document is not a specimen or sample (authenticity:specimen:). A payslip gets no document check. Its entry carries fields only.

Examples

Two files of one document (front and back of an ID card):

Limits and retention in the code