Code Examples
What Every Example Does
Each example uploads one file to POST /v1/extract and then follows the same steps:
- On
429 rate_limited,502,503or504: wait and try again, at most three times. If the answer has aRetry-Afterheader, wait the full number of seconds. These answers are not charged. - On
429 quota_exhaustedand on any other error: stop and report theerror.code. - On
200: readsuccess. If it istrue, use thefieldsof every document whose ownsuccessistrue. If it isfalse, readfailure_reason. The reasonno ocr engine availableis 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.
Every success is charged, also for a file you already sent before. Store the result on your side.
cURL
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:
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):
curl -s "https://api.idparse.com/v1/quota" \
-H "Authorization: Bearer YOUR_API_KEY"PHP
This example uses Guzzle (composer require guzzlehttp/guzzle).
<?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).
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.
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'));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.