Extract structured passport data from MRZ images with a single API call.
No API key needed for up to 10 free requests per day. Just send an image:
curl -X POST https://passport-ocr.com/v1/ocr \
-F "[email protected]"Import a pre-built collection into your favorite API client with all endpoints, variables, and example requests ready to go.
For paid usage with unlimited requests, include your API key in one of these headers:
Authorization: Bearer passport_ocr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX-API-Key: passport_ocr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAPI keys are generated from your dashboard after purchasing credits. Keys use the format passport_ocr_<32-char-hex>.
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/v1/ocr | POST | Optional | Extract MRZ data from a passport image |
/v1/credits | GET | API Key | Check your credit balance |
/v1/usage | GET | None | Check anonymous usage (based on fingerprint) |
/v1/health | GET | None | Health check and version info |
The /v1/ocr endpoint accepts two formats. Maximum file size is 10 MB.
POST /v1/ocr
Content-Type: multipart/form-data
Field: image (file)POST /v1/ocr
Content-Type: application/json
{
"image": "data:image/jpeg;base64,/9j/4AAQ..."
}{
"success": true,
"data": {
"documentType": "PASSPORT",
"documentNumber": "AB1234567",
"issuingCountry": "GBR",
"lastName": "SMITH",
"firstName": "JOHN",
"nationality": "GBR",
"dateOfBirth": "1990-01-15",
"sex": "M",
"expirationDate": "2030-06-20",
"personalNumber": ""
}
}{
"success": false,
"error": {
"code": "MRZ_NOT_DETECTED",
"message": "Could not detect an MRZ region in the uploaded image."
}
}Send the X-Dry-Run: true header to validate your image and detect the MRZ region without performing full OCR. This is free and does not deduct any credits.
curl -X POST https://passport-ocr.com/v1/ocr \
-H "X-Dry-Run: true" \
-F "[email protected]"For paid requests, include an Idempotency-Key header with a client-generated UUID. If you send the same key within 24 hours, you will receive the cached response without being charged again.
curl -X POST https://passport-ocr.com/v1/ocr \
-H "Authorization: Bearer passport_ocr_xxx" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-F "[email protected]"Idempotency keys are scoped to your API key and cached for 24 hours. This feature is only available for authenticated (paid) requests.
| Code | HTTP | Description |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Anonymous daily limit reached |
CAPACITY_EXCEEDED | 429 | Server at capacity (free tier) |
INSUFFICIENT_CREDITS | 402 | No credits remaining |
INVALID_API_KEY | 401 | API key not recognized |
INVALID_IMAGE | 400 | Image could not be parsed |
MRZ_NOT_DETECTED | 422 | MRZ region not found in image |
OCR_FAILED | 422 | MRZ detected but text unreadable |
MRZ_PARSE_FAILED | 422 | OCR text found but MRZ validation failed |
FILE_TOO_LARGE | 413 | Image exceeds 10 MB limit |
INTERNAL_ERROR | 500 | Unexpected server error |
curl -X POST https://passport-ocr.com/v1/ocr \
-H "Authorization: Bearer passport_ocr_xxx" \
-F "[email protected]"const form = new FormData();
form.append("image", fileInput.files[0]);
const response = await fetch("https://passport-ocr.com/v1/ocr", {
method: "POST",
headers: {
"Authorization": "Bearer passport_ocr_xxx",
},
body: form,
});
const result = await response.json();
console.log(result.data);import requests
response = requests.post(
"https://passport-ocr.com/v1/ocr",
headers={"Authorization": "Bearer passport_ocr_xxx"},
files={"image": open("passport.jpg", "rb")},
)
result = response.json()
print(result["data"])package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
file, _ := os.Open("passport.jpg")
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("image", "passport.jpg")
io.Copy(part, file)
writer.Close()
req, _ := http.NewRequest("POST", "https://passport-ocr.com/v1/ocr", body)
req.Header.Set("Authorization", "Bearer passport_ocr_xxx")
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
}$ch = curl_init("https://passport-ocr.com/v1/ocr");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer passport_ocr_xxx"],
CURLOPT_POSTFIELDS => ["image" => new CURLFile("passport.jpg")],
CURLOPT_RETURNTRANSFER => true,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($result["data"]);require "net/http"
require "json"
uri = URI("https://passport-ocr.com/v1/ocr")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer passport_ocr_xxx"
form_data = [["image", File.open("passport.jpg")]]
req.set_form(form_data, "multipart/form-data")
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.parse(res.body)["data"]import java.net.http.*;
import java.nio.file.Path;
var client = HttpClient.newHttpClient();
var body = HttpRequest.BodyPublishers.ofFile(Path.of("passport.jpg"));
var request = HttpRequest.newBuilder()
.uri(URI.create("https://passport-ocr.com/v1/ocr"))
.header("Authorization", "Bearer passport_ocr_xxx")
.header("Content-Type", "image/jpeg")
.POST(body)
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer passport_ocr_xxx");
using var content = new MultipartFormDataContent();
content.Add(new StreamContent(File.OpenRead("passport.jpg")), "image", "passport.jpg");
var response = await client.PostAsync("https://passport-ocr.com/v1/ocr", content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);Import these ready-made workflows into n8n to integrate Passport OCR into your automations. Copy the JSON below and paste it in n8n via Menu → Import from JSON.
The API key is pre-filled with PUT_YOUR_API_KEY_HERE which works for testing with anonymous rate limits (10/day). Replace it with your real key from the dashboard for production use.
A web form where users upload a passport image. The workflow sends it to the Passport OCR API and returns the extracted MRZ data.
{
"name": "Passport OCR — Form Upload",
"nodes": [
{
"parameters": {
"formTitle": "Passport OCR",
"formDescription": "Upload a passport image to extract MRZ data",
"formFields": {
"values": [
{
"fieldLabel": "Passport_Image",
"fieldType": "file",
"requiredField": true,
"acceptFileTypes": ".jpg,.jpeg,.png,.webp,.bmp,.tiff",
"multipleFiles": false
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.2,
"position": [
0,
208
],
"id": "f145d1cf-7c80-4bd0-be1a-246241fad1e4",
"name": "On form submission",
"webhookId": "passport-ocr-form"
},
{
"parameters": {
"method": "POST",
"url": "https://api.passport-ocr.com/v1/ocr",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-API-Key",
"value": "PUT_YOUR_API_KEY_HERE"
}
]
},
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "image",
"inputDataFieldName": "Passport_Image"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
288,
208
],
"id": "927d3f88-51f9-4bbf-abcd-09ffbe6c873f",
"name": "Passport OCR API"
}
],
"connections": {
"On form submission": {
"main": [
[
{
"node": "Passport OCR API",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"pinData": {},
"tags": []
}What this does
/v1/ocr and returns the parsed MRZ JSONUsers send a passport photo to your Telegram bot. The workflow extracts MRZ data and replies with the result.
{
"name": "Passport OCR — Telegram Bot",
"nodes": [
{
"parameters": {
"updates": [
"message"
],
"additionalFields": {
"download": true,
"imageSize": "large"
}
},
"type": "n8n-nodes-base.telegramTrigger",
"typeVersion": 1.2,
"position": [
0,
208
],
"id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"name": "Telegram Trigger",
"webhookId": "passport-ocr-telegram",
"credentials": {
"telegramApi": {
"id": "PASTE_CREDENTIAL_ID",
"name": "Telegram Bot API"
}
}
},
{
"parameters": {
"method": "POST",
"url": "https://api.passport-ocr.com/v1/ocr",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-API-Key",
"value": "PUT_YOUR_API_KEY_HERE"
}
]
},
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "image",
"inputDataFieldName": "data"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
288,
208
],
"id": "d4e5f6a7-b8c9-0123-defa-234567890123",
"name": "Passport OCR API"
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
"text": "=Passport OCR Result:\n\nName: {{ $json.data.firstName }} {{ $json.data.lastName }}\nNationality: {{ $json.data.nationality }}\nDocument: {{ $json.data.documentNumber }}\nDate of Birth: {{ $json.data.dateOfBirth }}\nExpiry: {{ $json.data.expirationDate }}\nSex: {{ $json.data.sex }}",
"additionalFields": {
"parse_mode": "Markdown"
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
576,
208
],
"id": "e5f6a7b8-c9d0-1234-efab-345678901234",
"name": "Send OCR Result",
"credentials": {
"telegramApi": {
"id": "PASTE_CREDENTIAL_ID",
"name": "Telegram Bot API"
}
}
}
],
"connections": {
"Telegram Trigger": {
"main": [
[
{
"node": "Passport OCR API",
"type": "main",
"index": 0
}
]
]
},
"Passport OCR API": {
"main": [
[
{
"node": "Send OCR Result",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"pinData": {},
"tags": []
}What this does
/v1/ocr as multipart form-dataAfter importing, connect your Telegram Bot API credentials (Settings → Credentials → Add "Telegram Bot API" with your bot token from @BotFather).
10/day
Resets at midnight UTC. No signup required.
Unlimited
Limited only by your credit balance. $0.01 per request.
See our pricing page for credit packages and details.