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
- Served322.2Kcalls
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. iApp keeps no copy; consent and notice under PDPA and GDPR remain with you as the data controller. 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. |