Passport OCR
Reads the machine-readable zone of any ICAO 9303 passport and returns the holder's details, the photograph, and whether each field agrees with its check digit.
/v3/store/ekyc/passportTry it- Price0.75 ICper page
- Measured95.5%
- Capacity15,000 passports/hour
- Served317.1Kcalls
Input

OutputPOST /v3/store/ekyc/passport
- number
- AA1234567
- valid_number
- true
- surname
- SPECIMEN
- names
- SOMCHAI
- date_of_birth
- 01/01/90
- valid_date_of_birth
- true
- expiration_date
- 31/12/30
- valid_expiration_date
- true
- nationality
- THA
- valid_composite
- true
Request
multipart/form-data, one passport per request; a PDF returns one entry per page.
Headers
apikeystringrequiredBody
filefilerequiredfieldsstringoptionsstringsegmentation corrects a badly oriented image, at roughly twice the time; no_thresh skips the pre-processing of the MRZ crop.The legacy paths /passport-ocr, /passport-ocr/v2 and /passport-ocr/v2/ocr reach the same service at the same price.
Response
A flat object. Act on valid_number: when it is false, the number cannot belong to a real passport, so capture the page again.
numberstringsurnamenamesdate_of_birthexpiration_dateDD/MM/YY; the MRZ does not encode the centurysexM, F, or < when unspecifiednationalitycountrycountry is the issuerpersonal_numbertypemrz_typeP< for an ordinary passport; TD3 for a passport MRZfacevalid_numbervalid_date_of_birthvalid_expiration_datevalid_personal_numbervalid_compositevalid_composite covers the MRZ as a wholevalid_scoreDiagnostics and status codes
| Field | Meaning |
|---|---|
check_number, check_date_of_birth, check_expiration_date, check_personal_number, check_composite | The check digits as printed |
raw_text | The two MRZ lines, 44 characters each |
method | How the MRZ band was located |
inference | Seconds |
file_name, message, status_code | Success and 200 on the happy path |
When no MRZ can be found the request still returns 200 with an Error Message field; options=segmentation usually resolves a badly oriented image. The service's own codes: 415 unsupported file type, 461 no file attached, 462 no file key in the form.
Details
Measured
Scored on a 266-passport benchmark by the MRZ's own check digits: a returned field either satisfies the digit printed on the passport or it does not.
| Measure | Result |
|---|---|
| MRZ parsed | 100% |
| Document number verified | 96.2% |
| Date of birth verified | 99.2% |
| Expiry date verified | 98.1% |
| Number, birth date and expiry all verified | 95.5% |
| Median time | 0.4 s per passport |
| Sustained throughput | 15,000 passports per hour, production, August 2026 |
A check digit is one decimal digit, so about one wrong read in ten passes it by chance; true accuracy is slightly under these figures. Method: the benchmark paper (PDF).
Limits
- The machine-readable zone only; text in the visual zone is not read.
Data handling
Images are processed in memory and not kept after the response. The service is GDPR and PDPA compliant. For an on-premise deployment, in which no passport leaves your network, contact us.
Changelog
| Version | Date | Changes |
|---|---|---|
| v2.0.5-20260825 | 25 Aug 2026 | Dates return as DD/MM/YY, the format since 2023, so a caller that parsed the interim YYMMDD form must update; adds type, mrz_type, method and valid_score. |
| v2.0.3-20260825 | 25 Aug 2026 | New recognition with structural MRZ validation: fully verified reads 58.6% to 95.5%, valid_date_of_birth and valid_expiration_date returned, on-premise deployment. |
| v2.0 | Feb 2023 | MRZ extraction with the face image and check-digit flags. |