Loading...
Loading...
Build a production-ready image OCR flow with retries, idempotency, and clear error handling.
Start with a single synchronous request for an image URL.
curl -X POST https://api.open-ocr.com/v1/ocr \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"engine": "mistral-mistral-ocr-4-1",
"input": {
"type": "url",
"url": "https://example.com/receipt.png"
},
"output_format": "json"
}'{
"request_id": "req_123",
"status": "succeeded",
"engine": "mistral-mistral-ocr-4-1",
"extracted_text": "TOTAL: $42.19",
"provider_latency_ms": 284,
"cost_debited": 0.005
}Always check status before using extracted text.
Retry on HTTP 429/5xx with backoff. Do not retry 4xx validation errors without changing input.
import fetch from "node-fetch";
async function ocrWithRetry(payload: object, maxAttempts = 3) {
// One Idempotency-Key per logical request, reused on every retry.
const idempotencyKey = crypto.randomUUID();
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const res = await fetch("https://api.open-ocr.com/v1/ocr", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + process.env.OPENOCR_API_KEY,
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify(payload),
});
// A completed JSON request returns HTTP 200: accept any 2xx and read the body's status.
if (res.ok) {
const body = await res.json();
if (body.status !== "succeeded") throw new Error("OCR ended as " + (body.status ?? body.error?.code)); // error envelopes have no status
return body;
}
if (res.status === 409) throw new Error("Idempotency-Key was used with a different request; use a new key");
if (res.status === 503 && (await res.clone().json()).status === "timeout") {
// A timeout replays as the same 503 for this key: do not retry the same key.
throw new Error("OCR timed out; retry with a NEW Idempotency-Key");
}
if (![429, 500, 502, 503, 504].includes(res.status)) {
throw new Error("Non-retryable status: " + res.status);
}
if (attempt === maxAttempts) {
throw new Error("OCR failed after " + maxAttempts + " attempts");
}
await new Promise((r) => setTimeout(r, 500 * attempt));
}
}For large files or queue-based processing, use async mode and a webhook callback.
Read webhook integration guide →