Zegi API
Extract text and structured data from images and PDFs — synchronously or asynchronously — with usage metering, signed webhooks and predictable, versioned responses. UAE-first, built for websites, mobile apps, ERP/POS/accounting systems and AI agents.
Fast & predictable
One JSON envelope, typed errors, request IDs.
Push & pull
Async jobs + signed webhooks.
AI-ready
OpenAPI 3.1 + llms.txt.
Authentication
Create a key in your API dashboard. Send it as a bearer token on every request. The key is shown once — store it securely and never expose it in client-side code or query strings.
Authorization: Bearer ajk_live_xxx.ajs_xxx
# or:
X-API-Key: ajk_live_xxx.ajs_xxxQuick start
- Create an API key with the
ocr:processscope. - POST a file to
/ocr. - Read
data.files[0].textfrom the response envelope.
curl -X POST "https://zegi.ae/api/v1/ocr" \
-H "Authorization: Bearer $ZEGI_API_KEY" \
-F "file=@document.png"Every keyed response is wrapped in a consistent envelope:
{
"success": true,
"request_id": "req_9f2c1a7b3d4e5f60",
"api_version": "v1",
"data": {
"files": [
{ "name": "document.png", "ok": true, "text": "…", "confidence": 96,
"engine": "paddleocr", "language": "en", "document_type": "invoice",
"structured": { /* invoice/receipt/passport when detected */ },
"pages": [ { "page": 1, "text": "…", "confidence": 96 } ] }
]
}
}OCR
POST /ocr accepts multipart file (or files). Supported inputs: JPG, PNG, WEBP, and PDFs with a text layer. Add ?includeLayout=true for per-line bounding boxes. Recognized documents (invoice, receipt, passport) also return a typed structured object; uncertain fields are null — never fabricated.
Async jobs
For large files, submit with ?async=true to get a 202 and a job_id, then poll GET /ocr/jobs/{id}. Send an Idempotency-Key header to safely retry submissions without duplicating work.
# 1) Submit — returns 202 with a job_id
curl -X POST "https://zegi.ae/api/v1/ocr?async=true" \
-H "Authorization: Bearer $ZEGI_API_KEY" \
-H "Idempotency-Key: my-unique-key-001" \
-F "file=@large.pdf"
# 2) Poll until status is "completed"
curl "https://zegi.ae/api/v1/ocr/jobs/JOB_ID" \
-H "Authorization: Bearer $ZEGI_API_KEY"Webhooks
Register an endpoint (POST /webhooks) to receive events. Each delivery is signed — verify the X-Zegi-Signature header (HMAC-SHA256 over `${timestamp}.${body}`) and reject timestamps older than 5 minutes. The legacy X-AjmanOCR-Signature header is still sent for backward compatibility.
Events: ocr.completedocr.failedtool.completedtool.failed
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, headers, secret) {
const ts = headers["x-zegi-timestamp"] ?? headers["x-ajmanocr-timestamp"]; // legacy fallback
const sig = headers["x-zegi-signature"] ?? headers["x-ajmanocr-signature"]; // "v1=<hex>"
const expected = "v1=" + createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // replay window
return sig.length === expected.length && timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}Scopes
ocr:read | Read OCR jobs and results. |
ocr:process | Submit documents for OCR processing. |
documents:read | Read stored documents and their OCR results. |
documents:write | Create, update and delete stored documents. |
compression:read | Read compression jobs and results. |
compression:process | Submit files for compression or conversion. |
exports:read | Export OCR results in supported formats. |
usage:read | Read account usage, limits and API-key status. |
webhooks:read | Read webhook endpoints and delivery status. |
webhooks:write | Create, update and delete webhook endpoints. |
pdf:merge | Merge multiple PDFs into one. |
pdf:split | Split a PDF into pages or ranges. |
pdf:convert | Convert PDFs to Word/Excel. |
pdf:searchable | Create searchable PDFs from images/PDFs. |
image:enhance | Enhance and upscale images. |
Errors
Errors use the same envelope with a stable error.code and an HTTP status. Never parse the message — switch on the code.
| Code | HTTP | Meaning |
|---|---|---|
MISSING_API_KEY | 401 | An API key is required. Provide it as 'Authorization: Bearer <key>'. |
INVALID_API_KEY | 401 | The API key is invalid. |
API_KEY_REVOKED | 401 | This API key has been revoked. |
API_KEY_EXPIRED | 401 | This API key has expired. |
IP_NOT_ALLOWED | 403 | This API key is not permitted from your IP address. |
ACCOUNT_INACTIVE | 403 | This account is not active. |
INSUFFICIENT_SCOPE | 403 | This API key lacks the scope required for this operation. |
API_ACCESS_NOT_ENABLED | 403 | API processing is not enabled for this account. |
API_DISABLED | 503 | The API is temporarily unavailable. |
WORKER_UNAVAILABLE | 503 | The processing service is temporarily unavailable. |
STORAGE_UNAVAILABLE | 503 | File storage is temporarily unavailable. Please try again. |
SERVICE_UNAVAILABLE | 503 | The service is temporarily unavailable. |
RATE_LIMITED | 429 | Too many requests. Please slow down and retry later. |
USAGE_LIMIT_EXCEEDED | 429 | Your page allowance has been reached. |
INVALID_REQUEST | 400 | The request is invalid. |
FILE_TOO_LARGE | 413 | The uploaded file exceeds the maximum allowed size. |
UNSUPPORTED_FILE_TYPE | 415 | This file type is not supported. |
INVALID_DOCUMENT | 422 | The document could not be processed. |
OCR_FAILED | 500 | OCR processing failed. Please try again. |
OCR_TIMEOUT | 504 | OCR processing timed out. |
NOT_FOUND | 404 | The requested resource was not found. |
JOB_NOT_FOUND | 404 | The requested job was not found. |
CONFLICT | 409 | The request conflicts with the current state. |
SERVER_ERROR | 500 | An unexpected error occurred. |
Rate limits & limits
- Max file size: 25 MB (admin-configurable).
- Max pages processed per document: 30.
- Page allowance & per-key rate limits depend on your plan — see
GET /account. - 1 image = 1 page; a PDF counts its text-layer pages.
- Rate-limited requests return
429 RATE_LIMITED; allowance exhaustion returns429 USAGE_LIMIT_EXCEEDED.
AI integration guide
Building with an AI coding agent (Claude Code, Cursor, Lovable, Bolt, Replit, v0)? Point it at the machine-readable spec and paste this prompt. The agent will follow the real contract instead of guessing.
You are integrating the Zegi API into my application.
Read the OpenAPI specification at https://zegi.ae/api/openapi.json and follow it exactly.
Authenticate with 'Authorization: Bearer <API_KEY>'. Respect the documented scopes,
limits, error codes and the JSON response envelope. For large files submit with
?async=true and poll GET /ocr/jobs/{id}. Verify webhook signatures using the
X-Zegi-Signature header (the legacy X-AjmanOCR-Signature is also sent). Do not invent endpoints or parameters.Machine-readable: openapi.json, openapi.yaml, llms.txt, llms-full.txt.
OpenAPI & SDKs
The full contract is published as OpenAPI 3.1. Generate a typed client in your language with any OpenAPI generator, or use the examples above directly.
# Example: generate a client from the spec
npx @openapitools/openapi-generator-cli generate \
-i https://zegi.ae/api/openapi.json \
-g typescript-fetch -o ./zegi-clientChangelog
- Keyed API with API keys, scopes and usage metering
- OCR API (sync + async jobs) with idempotency
- Outbound webhooks with HMAC signatures + retries
- OpenAPI 3.1, llms.txt and this documentation