Skip to main content

🛂 Passport OCR

🛂 พาสปอร์ต

Version Status New Route Route Route Route

Welcome to iApp Passport OCR API, an AI product developed by iApp Technology Co., Ltd. Our API is designed to automatically recognize and extract information from scanned passport images with high accuracy and speed. The system specifically focuses on reading the Machine Readable Zone (MRZ) at the bottom of passport pages, extracting crucial information like the holder's name, nationality, date of birth, and more.

Try Demo!

Example Images (Click to try)

Example 1

Getting Started

  1. Prerequisites

    • An API key from iApp Technology
    • Scanned passport images (profile page)
    • Supported file formats: JPEG, JPG, PNG, PDF
    • Maximum file size: 10MB
  2. Quick Start

    • Fast processing (1-2 seconds per image)
    • High accuracy text extraction (95.51%)
    • Support for multiple file formats
  3. Key Features

    • Extracts information from TD3 type MRZ
    • OCR accuracy scoring and validation
    • Face image extraction in base64 format
    • Support for multiple page PDF documents
    • Handles rotated and skewed images
    • Image segmentation pre-processing for skewed images
    • Supports Thai and English language
  4. Security & Compliance

    • GDPR and PDPA compliant
    • No data retention after processing
How to get API Key?

Please visit API Key Management page to view your existing API key or request a new one.

Example

Profile Page

Example Passport Profile Page

Request:

curl -X POST https://api.iapp.co.th/v3/store/ekyc/passport/v2 \
-H "apikey: YOUR_API_KEY" \
-F "file=@/path/to/passport.jpg"

Response:

{
"check_composite": "4",
"check_date_of_birth": "4",
"check_expiration_date": "4",
"check_number": "6",
"check_personal_number": "3",
"country": "THA",
"date_of_birth": "930710",
"expiration_date": "250304",
"method": "direct",
"mrz_type": "TD3",
"names": "MATHANIDA",
"nationality": "THA",
"number": "AC1062346",
"personal_number": "0012345678913",
"raw_text": "P<THAPOSHNASWADIWONG<<MATHANIDA<<<<<<<<<<<<<\nAC10623466THA9307104F25030440012345678913<34",
"sex": "F",
"surname": "POSHNASWADIWONG",
"type": "P",
"valid_composite": true,
"valid_date_of_birth": true,
"valid_expiration_date": true,
"valid_number": true,
"valid_personal_number": true,
"valid_score": 100,
"face": "/9j/4AAQSkZJRgABAQAAAQABAAD/..."
}

Response Fields Explanation

FieldDescriptionFormatExample
check_compositeOverall check digit for upper and middle machine readable linesSingle digit"4"
check_date_of_birthCheck digit for date of birth fieldSingle digit"4"
check_expiration_dateCheck digit for expiration date fieldSingle digit"4"
check_numberCheck digit for document numberSingle digit"6"
check_personal_numberCheck digit for personal numberSingle digit"3"
countryCountry code of passport issuance3 letters"THA"
date_of_birthDate of birthYYMMDD"930710"
expiration_dateDocument expiry dateYYMMDD"250304"
methodReading method usedString"direct"
mrz_typeType of machine readable zoneString"TD3"
namesFirst/given name(s)String"MATHANIDA"
nationalityNationality of holder3 letters"THA"
numberPassport numberString"AC1062346"
personal_numberNational ID numberString"0012345678913"
raw_textRaw MRZ text from passportString"P<THAPOSHNASWADIWONG..."
sexGenderSingle letter"F"
surnameLast/family nameString"POSHNASWADIWONG"
typeDocument typeString"P"
valid_compositeOverall MRZ validity checkBooleantrue
valid_date_of_birthDate of birth check digit validityBooleantrue
valid_expiration_dateExpiry date check digit validityBooleantrue
valid_numberDocument number check digit validityBooleantrue
valid_personal_numberPersonal number check digit validityBooleantrue
valid_scoreOverall validity scoreInteger 0-100100
faceExtracted face imageBase64 string"/9j/4AAQSkZJRgABA..."

PDF File Processing

When processing PDF files, the response format differs slightly:

  1. The response will be a JSON array containing results for each page
  2. Each page result includes:
    • page: Page number
    • info: Contains all the standard fields as shown above
  3. A process_time field shows total processing duration

Example PDF response structure:

[
{
"page": 1,
"info": {
"sex": "F",
"number": "AC1062346",
"expiration_date": "04/03/25",
"raw_text": "P<THAPOSHNASWADIWONG<<MATHANIDA<<<<<<<<<<<<<\nAC10623466THA9307104F25030440012345678913<34",
"personal_number": "0012345678913",
"surname": "POSHNASWADIWONG",
"nationality": "THA",
"date_of_birth": "10/07/93",
"names": "MATHANIDA",
"country": "THA",
"face": "iVBORw0...CYII=",
"inference": "3.888",
"file_name": "1676365480.3823211_thai_passport_page_1.png",
"message": "Success",
"status_code": 200
}
},
{
"process_time": "4.918s"
}
]

Features & Capabilities

Core Features

  • MRZ (Machine Readable Zone) text extraction
  • Face image extraction
  • Multiple page PDF support
  • Automatic image orientation correction
  • Image segmentation for skewed images
  • High accuracy validation checks

Supported Fields

  • Document type
  • Issuing country
  • Document number
  • Holder's name
  • Nationality
  • Date of birth
  • Gender
  • Expiration date
  • Personal number
  • Face image (base64)
  • Raw MRZ text
  • Validation scores

API Endpoints

EndpointMethodDescriptionCost
/v3/store/ekyc/passport/v2
/passport-ocr/v2 (legacy)
POSTEnhanced Passport OCR with 95.51% accuracy - extracts MRZ data and face image0.75 IC per page
/v3/store/ekyc/passport/v1
/passport-ocr (legacy)
POSTPassport OCR - extracts MRZ data and face image0.75 IC per page

API Reference

Passport OCR Endpoints

1. Passport OCR (Version 1)

POST /v3/store/ekyc/passport/v1

Performs OCR on passport profile page and extracts MRZ data.


2. Passport OCR (Version 2)

POST /v3/store/ekyc/passport/v2

Enhanced version with improved accuracy (95.51%). Performs OCR on passport profile page and extracts MRZ data.

Request Headers

NameTypeRequiredDescription
apikeystringYesYour API key

Request Body (multipart/form-data)

ParameterTypeRequiredDescription
fileFileYesImage file (JPG, PNG, PDF)
optionsStringNoEnable "segmentation" for skewed image processing

Code Examples

Curl

curl -X POST https://api.iapp.co.th/v3/store/ekyc/passport/front \
-H "apikey: YOUR_API_KEY" \
-F "file=@/path/to/file.jpg"

Python

import requests

url = "https://api.iapp.co.th/v3/store/ekyc/passport/v2"
headers = {
"apikey": "YOUR_API_KEY"
}
files = {
"file": open("passport.jpg", "rb")
}

response = requests.post(url, headers=headers, files=files)
print(response.json())

JavaScript

const axios = require("axios")
const FormData = require("form-data")
const fs = require("fs")

let data = new FormData()
data.append("file", fs.createReadStream("passport.jpg"))

let config = {
method: "post",
url: "https://api.iapp.co.th/v3/store/ekyc/passport/v2",
headers: {
apikey: "YOUR_API_KEY",
...data.getHeaders(),
},
data: data,
}

axios(config)
.then((response) => console.log(response.data))
.catch((error) => console.log(error))

PHP

<?php
$curl = curl_init();

curl_setopt_array($curl, array(
CURLOPT_URL => 'https://api.iapp.co.th/v3/store/ekyc/passport/v2',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => array(
'apikey: YOUR_API_KEY'
),
CURLOPT_POSTFIELDS => array(
'file'=> new CURLFILE('passport.jpg')
)
));

$response = curl_exec($curl);
curl_close($curl);
echo $response;

Swift

import Foundation

let url = URL(string: "https://api.iapp.co.th/v3/store/ekyc/passport/v2")!
let boundary = "Boundary-\(UUID().uuidString)"

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("YOUR_API_KEY", forHTTPHeaderField: "apikey")
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

let imageData = try! Data(contentsOf: URL(fileURLWithPath: "passport.jpg"))

var body = Data()
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"passport.jpg\"\r\n")
body.append("Content-Type: image/jpeg\r\n\r\n")
body.append(imageData)
body.append("\r\n--\(boundary)--\r\n")

let task = URLSession.shared.uploadTask(with: request, from: body) { data, response, error in
if let data = data {
let json = try? JSONSerialization.jsonObject(with: data)
print(json ?? "")
}
}
task.resume()

Kotlin

import okhttp3.*
import java.io.File

val client = OkHttpClient()

val file = File("passport.jpg")
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file",
file.name,
RequestBody.create(MediaType.parse("image/jpeg"), file)
)
.build()

val request = Request.Builder()
.url("https://api.iapp.co.th/v3/store/ekyc/passport/v2")
.addHeader("apikey", "YOUR_API_KEY")
.post(requestBody)
.build()

client.newCall(request).execute().use { response ->
println(response.body()?.string())
}

Java

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.*;

public class PassportOCR {
public static void main(String[] args) throws IOException {
String boundary = "Boundary-" + System.currentTimeMillis();
URL url = new URL("https://api.iapp.co.th/v3/store/ekyc/passport/v2");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("apikey", "YOUR_API_KEY");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (OutputStream os = conn.getOutputStream()) {
byte[] fileBytes = Files.readAllBytes(Paths.get("passport.jpg"));

os.write(("--" + boundary + "\r\n").getBytes());
os.write(("Content-Disposition: form-data; name=\"file\"; filename=\"passport.jpg\"\r\n").getBytes());
os.write(("Content-Type: image/jpeg\r\n\r\n").getBytes());
os.write(fileBytes);
os.write(("\r\n--" + boundary + "--\r\n").getBytes());
}

try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}

Dart

import 'package:http/http.dart' as http;
import 'dart:io';

Future<void> scanPassport() async {
var url = Uri.parse('https://api.iapp.co.th/v3/store/ekyc/passport/v2');
var request = http.MultipartRequest('POST', url);

request.headers['apikey'] = 'YOUR_API_KEY';

request.files.add(
await http.MultipartFile.fromPath(
'file',
'passport.jpg',
),
);

var response = await request.send();
var responseBody = await response.stream.bytesToString();
print(responseBody);
}

Limitations and Best Practices

Limitations

  • Maximum file size: 10MB
  • Supported formats: JPG, PNG, PDF
  • One passport per image
  • Clear, focused images required

Best Practices

  • Ensure good lighting conditions
  • Avoid glare and reflections
  • Center the passport in frame
  • Keep the passport flat
  • Use high resolution images
  • Enable segmentation option for skewed images

Accuracy & Performance

Overall Accuracy

  • Current Version (2.0): 95.51%
  • Previous Version (1.1): 88.86%

Field-Level Accuracy (Version 1.1)

  • Name: 81.93%
  • Surname: 90.26%
  • Document Number: 84.03%
  • Nationality: 88.09%
  • Face Detection: 100%

Processing Speed

  • Single image: 1-2 seconds
  • PDF documents: 2-3 seconds per page
  • Additional time when using segmentation

Factors Affecting Accuracy

  • Image quality
  • Lighting conditions
  • Document positioning
  • Image resolution
  • Document condition
  • Image skew angle

History

Version 2.0 (February 2023)

  • Increased overall accuracy from 88.86% to 95.51%
  • Upgraded entire OCR engine
  • Added image segmentation pre-processing for skewed images

Version 1.1 (January 2023)

  • Added face extraction to base64
  • Added support for slightly tilted images
  • Added PDF file support
  • Added multiple page PDF support

Version 1.0 (February 2022)

  • Initial release
  • Support for all country passports using MRZ
  • Basic image format support (PNG, JPG, JPEG)

Pricing

OperationProduction PathLegacy PathIC CostUnitOn-Premise
Passport OCR (Version 1)/v3/store/ekyc/passport/v1/passport-ocr0.75 ICper 1 requestContact us
Passport OCR (Version 2)/v3/store/ekyc/passport/v2/passport-ocr/v20.75 ICper 1 requestContact us