IDPARSE

Code Examples


What Every Example Does

Each example uploads one file to POST /v1/extract and then follows the same steps:

  1. On 429 rate_limited, 502, 503 or 504: wait and try again, at most three times. If the answer has a Retry-After header, wait the full number of seconds. These answers are not charged.
  2. On 429 quota_exhausted and on any other error: stop and report the error.code.
  3. On 200: read success. If it is true, use the fields of every document whose own success is true. If it is false, read failure_reason. The reason no ocr engine available is a temporary fault of the service, so you can send the same file again later. Every other reason needs a better image, not a retry.

Replace YOUR_API_KEY with your actual API key. Keep the key on your server, never in browser code.

Important

Every success is charged, also for a file you already sent before. Store the result on your side.

cURL

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

Show the status and the response headers too:

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

Check your usage (free of charge):

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

PHP

This example uses Guzzle (composer require guzzlehttp/guzzle).

php
<?php

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Utils;

$apiKey = getenv('IDPARSE_API_KEY');
$path = 'passport.jpg';

$client = new Client([
    'base_uri' => 'https://api.idparse.com/v1/',
    'http_errors' => false, // read error answers instead of throwing
    'timeout' => 100,
]);

for ($attempt = 1; $attempt <= 3; $attempt++) {
    $response = $client->post('extract', [
        'headers' => ['Authorization' => 'Bearer '.$apiKey],
        'multipart' => [
            ['name' => 'file', 'contents' => Utils::tryFopen($path, 'r')],
        ],
    ]);

    $status = $response->getStatusCode();
    $body = json_decode((string) $response->getBody(), true);
    $code = $body['error']['code'] ?? null;

    $canRetry = in_array($status, [502, 503, 504], true)
        || ($status === 429 && $code === 'rate_limited');

    if ($canRetry && $attempt < 3) {
        // Not charged. Wait the full Retry-After value.
        $wait = (int) ($response->getHeaderLine('Retry-After') ?: 5);
        sleep($wait);

        continue;
    }

    break;
}

if ($status !== 200) {
    fwrite(STDERR, "Request failed: HTTP $status, code $code".PHP_EOL);
    fwrite(STDERR, 'Request ID: '.$response->getHeaderLine('X-Request-ID').PHP_EOL);
    exit(1);
}

if ($body['success'] === true) {
    // Charged as one scan, also when the file holds several documents.
    foreach ($body['documents'] as $document) {
        if ($document['success'] !== true) {
            continue; // not verified: see "Partial Results"
        }
        echo 'Document number: '.$document['fields']['document_number'].PHP_EOL;
        echo 'Surname: '.($document['fields']['surname'] ?? 'not readable').PHP_EOL;
    }
} elseif ($body['failure_reason'] === 'no ocr engine available') {
    // Free of charge. A temporary fault of the service: send the same file again later.
    echo 'Service not ready, try again later.'.PHP_EOL;
} else {
    // Free of charge. Ask for a better image, do not send the same file again.
    echo 'Not readable: '.$body['failure_reason'].PHP_EOL;
}

echo 'Scans remaining: '.$response->getHeaderLine('X-IDParse-Scans-Remaining').PHP_EOL;

Python

This example uses requests (pip install requests).

python
import os
import sys
import time

import requests

API_KEY = os.environ["IDPARSE_API_KEY"]
URL = "https://api.idparse.com/v1/extract"
PATH = "passport.jpg"

for attempt in range(1, 4):
    with open(PATH, "rb") as handle:
        response = requests.post(
            URL,
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": handle},
            timeout=100,
        )

    body = response.json()
    code = body.get("error", {}).get("code")

    can_retry = response.status_code in (502, 503, 504) or (
        response.status_code == 429 and code == "rate_limited"
    )

    if can_retry and attempt < 3:
        # Not charged. Wait the full Retry-After value.
        wait = int(response.headers.get("Retry-After", 5))
        time.sleep(wait)
        continue

    break

if response.status_code != 200:
    print(f"Request failed: HTTP {response.status_code}, code {code}", file=sys.stderr)
    print("Request ID:", response.headers.get("X-Request-ID"), file=sys.stderr)
    sys.exit(1)

if body["success"]:
    # Charged as one scan, also when the file holds several documents.
    for document in body["documents"]:
        if not document["success"]:
            continue  # not verified: see "Partial Results"
        print("Document number:", document["fields"]["document_number"])
        print("Surname:", document["fields"]["surname"] or "not readable")
elif body["failure_reason"] == "no ocr engine available":
    # Free of charge. A temporary fault of the service: send the same file again later.
    print("Service not ready, try again later.")
else:
    # Free of charge. Ask for a better image, do not send the same file again.
    print("Not readable:", body["failure_reason"])

print("Scans remaining:", response.headers.get("X-IDParse-Scans-Remaining"))

Node.js

This example needs Node.js 18 or newer. It uses the built-in fetch, FormData and Blob, so it has no dependencies. Save it as an ES module, for example extract.mjs.

javascript
import { readFile } from 'node:fs/promises';

const API_KEY = process.env.IDPARSE_API_KEY;
const ENDPOINT = 'https://api.idparse.com/v1/extract';
const PATH = 'passport.jpg';

const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));

const bytes = await readFile(PATH);

let response;
let body;
let code;

for (let attempt = 1; attempt <= 3; attempt++) {
    const form = new FormData();
    form.append('file', new Blob([bytes]), 'document.jpg');

    response = await fetch(ENDPOINT, {
        method: 'POST',
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: form,
    });

    body = await response.json();
    code = body.error?.code;

    const canRetry = [502, 503, 504].includes(response.status)
        || (response.status === 429 && code === 'rate_limited');

    if (canRetry && attempt < 3) {
        // Not charged. Wait the full Retry-After value.
        const wait = Number(response.headers.get('Retry-After') ?? 5);
        await sleep(wait);
        continue;
    }

    break;
}

if (response.status !== 200) {
    console.error(`Request failed: HTTP ${response.status}, code ${code}`);
    console.error('Request ID:', response.headers.get('X-Request-ID'));
    process.exit(1);
}

if (body.success) {
    // Charged as one scan, also when the file holds several documents.
    for (const document of body.documents) {
        if (!document.success) {
            continue; // not verified: see "Partial Results"
        }
        console.log('Document number:', document.fields.document_number);
        console.log('Surname:', document.fields.surname ?? 'not readable');
    }
} else if (body.failure_reason === 'no ocr engine available') {
    // Free of charge. A temporary fault of the service: send the same file again later.
    console.log('Service not ready, try again later.');
} else {
    // Free of charge. Ask for a better image, do not send the same file again.
    console.log('Not readable:', body.failure_reason);
}

console.log('Scans remaining:', response.headers.get('X-IDParse-Scans-Remaining'));
Note

Do not set the Content-Type header yourself in any of these examples. The HTTP library adds the multipart boundary (the separator between the form parts) for you.