IDPARSE

Endpoints


All endpoints require an API key. See Authentication.

The extract endpoint answers with flat JSON without a data wrapper. The quota endpoint uses a data and meta wrapper. Error responses return "success": false with an error object. See Error Handling.


Extract

Read the data of one identity document.

text
POST /v1/extract

The request body is a multipart form (multipart/form-data) with exactly one file.

Parameter Type Required Description
file form file Yes The document file. Exactly one file, not empty, at most 25 MB

One uploaded file is one scan, also when it holds several documents.

Example request:

bash
curl -s -X POST "https://api.idparse.com/v1/extract" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@passport.jpg"
Note

A missing file, an empty file, or more than one file in the file field gives 422 invalid_file. A file that is larger than 25 MB gives 413 file_too_large. Both answers are free of charge.

Supported Files and Documents

Supported input files: JPEG, PNG, PDF, TIFF, BMP, WebP and HEIF/HEIC (iPhone photos).

File Type Notes
JPEG, PNG, TIFF, BMP and WebP images One or more documents per image
HEIF/HEIC images The format of iPhone photos
PDF files At most the first 3 pages are read

The file type is recognised from the file content, not from the file name.

Supported documents:

The document must carry an MRZ (machine readable zone, the lines of letters, digits and < signs at the bottom of the document) as defined by the standard ICAO 9303.

Document MRZ Format
Passports TD3
ID cards TD1, TD2
Visas MRV-A, MRV-B
Important

A document without an MRZ cannot be read. Many driving licences and older ID cards have no MRZ.

Answer: Success

HTTP status 200 and "success": true. At least one document was found, and all three of its check digits (control numbers that are printed inside the MRZ) matched. This answer is charged as one scan.

json
{
    "success": true,
    "documents": [
        {
            "success": true,
            "document_type": "TD3",
            "fields": {
                "surname": "ERIKSSON",
                "given_names": "ANNA MARIA",
                "birth_date": "1974-08-12",
                "sex": "F",
                "nationality": "UTO",
                "document_number": "L898902C3",
                "expiry_date": "2012-04-15",
                "issuing_country": "UTO"
            },
            "check_digits_valid": {
                "document_number": true,
                "birth_date": true,
                "expiry_date": true
            },
            "checksum_protected": {
                "surname": false,
                "given_names": false,
                "birth_date": true,
                "sex": false,
                "nationality": false,
                "document_number": true,
                "expiry_date": true,
                "issuing_country": false
            },
            "failure_reason": null,
            "notes": [
                "birth date century inferred",
                "expiry date century inferred"
            ],
            "page": 1,
            "region": { "x": 0.05, "y": 0.81, "width": 0.9, "height": 0.12 }
        }
    ],
    "document_count": 1,
    "verified_document_count": 1,
    "processing_complete": true,
    "truncation_reason": null,
    "failure_reason": null,
    "notes": ["engines tried: locator"],
    "duration_ms": 480,
    "service_version": "2.0.0"
}

The example shows the public ICAO specimen passport. The meaning of every field is explained in Results and Billing.

Answer: Several Documents

One file can hold several documents, for example two passports scanned on one page. Each one is an entry of documents, in page order and from top to bottom. Check success of each entry: a file is a success when at least one document was verified. The file is charged as one scan.

json
{
    "success": true,
    "documents": [
        { "success": true, "document_type": "TD3", "page": 1, "...": "first passport, as above" },
        { "success": true, "document_type": "TD3", "page": 1, "...": "second passport, as above" }
    ],
    "document_count": 2,
    "verified_document_count": 2,
    "processing_complete": true,
    "truncation_reason": null,
    "failure_reason": null,
    "notes": ["engines tried: locator"],
    "duration_ms": 16000,
    "service_version": "2.0.0"
}

The "..." keys stand for the other document fields of the success example. When a limit stopped the work early, processing_complete is false and truncation_reason names the limit. See Several Documents in One File.

Answer: Unreadable Document

HTTP status 200 and "success": false. The request itself was fine, but no document could be read. The failure_reason field holds one of ten fixed texts, and documents is usually empty. This answer is free of charge.

json
{
    "success": false,
    "documents": [],
    "document_count": 0,
    "verified_document_count": 0,
    "processing_complete": true,
    "truncation_reason": null,
    "failure_reason": "no machine readable zone found",
    "notes": ["engines tried: locator, tesseract"],
    "duration_ms": 480,
    "service_version": "2.0.0"
}

All ten failure reasons are listed in Results and Billing.

Answer: Partial Result

HTTP status 200 and "success": false, but a document has some fields filled. This happens when the MRZ was found, but not every check digit matched. This answer is free of charge.

json
{
    "success": false,
    "documents": [
        {
            "success": false,
            "document_type": "TD3",
            "fields": {
                "surname": "ERIKSSON",
                "given_names": "ANNA MARIA",
                "birth_date": "1974-08-12",
                "sex": "F",
                "nationality": "UTO",
                "document_number": "L898902C3",
                "expiry_date": null,
                "issuing_country": "UTO"
            },
            "check_digits_valid": {
                "document_number": true,
                "birth_date": true,
                "expiry_date": false
            },
            "checksum_protected": {
                "surname": false,
                "given_names": false,
                "birth_date": true,
                "sex": false,
                "nationality": false,
                "document_number": true,
                "expiry_date": true,
                "issuing_country": false
            },
            "failure_reason": "mrz found but check digits failed",
            "notes": [
                "partial read: trust only fields whose check digit passed"
            ],
            "page": 1,
            "region": null
        }
    ],
    "document_count": 1,
    "verified_document_count": 0,
    "processing_complete": true,
    "truncation_reason": null,
    "failure_reason": "mrz found but check digits failed",
    "notes": ["engines tried: locator, tesseract"],
    "duration_ms": 480,
    "service_version": "2.0.0"
}
Important

In a partial result, trust only a protected field whose entry in check_digits_valid is true. A protected field that is not trusted is null, like the expiry date in the example above. The document's notes array holds the text partial read: trust only fields whose check digit passed. See Partial Results.

Response headers of the extract endpoint:

Extract answers carry Cache-Control: no-store and the four usage headers X-IDParse-Scans-Included, X-IDParse-Scans-Used, X-IDParse-Scans-Remaining and X-IDParse-Period-Ends. Cache-Control: no-store is present on every answer that passed the key check and the maintenance check. The four usage headers are present only when the monthly usage check returned a result. They can be missing on early rejections (401, 403, 503 maintenance), on 429 rate_limited, on 503 service_unavailable when the usage check itself failed, and for accounts without a monthly limit. See Limits and Quota.


Quota

Check your plan, your included scans and your usage in the current month.

text
GET /v1/quota

This endpoint is free of charge. It never counts as a scan, and it stays reachable after your included scans are used up. It has no parameters.

Example request:

bash
curl -s "https://api.idparse.com/v1/quota" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example response:

json
{
    "success": true,
    "data": {
        "plan": "Starter",
        "quota": {
            "base_limit": 500,
            "effective_limit": 500,
            "used": 127,
            "remaining": 373,
            "overflow_allowed": false,
            "overflow_percent": 0
        },
        "period": "monthly",
        "resets_at": "2026-10-01T00:00:00+00:00"
    },
    "meta": {
        "timestamp": "2026-09-20T14:30:00+00:00"
    }
}
Field Description
data.plan The name of your plan. It is always given in English
data.quota.base_limit The scans that are included in your plan per month
data.quota.effective_limit The highest number of scans you can use this month. It is equal to base_limit unless overage (use above the included scans) is allowed for your account
data.quota.used The usage count of the current month. It can include scans that are still being processed
data.quota.remaining effective_limit minus used, never below 0
data.quota.overflow_allowed true when overage is allowed for your account
data.quota.overflow_percent The allowed overage in percent of base_limit
data.period monthly: the included scans start again every calendar month. lifetime: the scans of the free trial are given once and do not come back
data.resets_at The moment the usage is set back to 0: the first day of the next calendar month, 00:00 UTC. null for the free trial, because its scans never start again
meta.timestamp The time of this answer
Note

When monthly limiting is switched off for an account, effective_limit and remaining are 0 although scans stay allowed. The usage count can include scans that are still being processed. It cannot confirm whether one interrupted request was charged.

Note

The plan name and the numbers in the example are placeholders. The quota endpoint counts toward the per minute request limit.