- 50 extractions/month
- 10 requests/minute
- Up to 2 MB image size
- Auto language detection
- English OCR (eng)
- Plain text + markdown output
Image to Text (OCR) API
Convert any image into clean text and markdown using advanced OCR. Send a photo, screenshot, scan, bill, or signage and get the text back instantly — with automatic language detection across 30+ languages.
Built for every image-to-text workflow
Image OCR is a powerful API that extracts text and structured markdown from any image using advanced OCR — photos, screenshots, scanned documents, receipts, signage, handwriting, and multi-column layouts.
Advanced OCR
High-accuracy text recognition for photos, screenshots, and low-quality scans — even noisy or skewed images.
Auto Language Detect
Leave lang blank and the engine detects the script automatically — no need to know the language upfront.
30+ Languages
English, Hindi, Arabic, Chinese, Japanese, Spanish, French, and more — including multilingual combinations.
Text & Markdown
Get both plain text and structured markdown — paragraphs rebuilt from wrapped lines, caps lines promoted to headings.
Instant Response
Fully synchronous — no job ID, no polling, no webhooks. Send an image, get the text back in the same response.
Multiple Input Modes
Upload directly, send a public image URL, a Google Drive link, an extensionless image URL, or base64 data.
Rich Metrics
Every response includes character, word, and line counts, detected script + confidence, and processing time.
Developer Friendly
Simple REST API, flexible input formats, clear error messages, and consistent JSON responses.
Simple, transparent pricing
Start free and scale as you grow. No hidden fees.
- 500 extractions/month
- 20 requests/minute
- Up to 6 MB image size
- Auto language detection
- All 30+ languages (incl. multilingual)
- Plain text + markdown output
- Email support
- 2,000 extractions/month
- 60 requests/minute
- Up to 12 MB image size
- Auto language detection
- All 30+ languages (incl. multilingual)
- Plain text + markdown output
- Priority support
- 5,000 extractions/month
- 60 requests/minute
- Up to 15 MB image size
- Auto language detection
- All 30+ languages (incl. multilingual)
- Plain text + markdown output
- Accelerated processing
- Dedicated support
- Unlimited extractions
- Custom rate limits
- Up to 50 MB image size
- Auto language detection
- All 30+ languages
- Plain text + markdown output
- Webhook callbacks
- 24/7 priority support
API reference
Everything you need to integrate the Image to Text (OCR) API.
Authentication
All API requests require authentication using your API key. Send it via the x-api-key header with every request.
x-api-key: your_api_key_here Get your API key. Sign up at dash.corenexis.com to get your API key instantly.
API endpoint
The API exposes a single synchronous endpoint. Send one image, get the extracted text and markdown back in the same response — there is no job ID and no polling.
Extract text from an image
POSThttps://api.corenexis.com/image-ocr/v1
Synchronous by design. One request in, full text out. No queue, no job_id, no status checks. Only successful extractions consume monthly quota.
How it works
The API is synchronous and processes exactly one image per request. The full lifecycle happens inside a single HTTP call.
- Send the image — Send a
POSTrequest to/image-ocr/v1with the image (file upload, URL, or base64) and an optionallang. The API reads the image, detects its MIME type, and measures its size. - Validation against your plan — Your API key, subscription, rate limit, and image size are checked against your plan. If
langis provided but unsupported, the request is rejected immediately — before any processing or quota check. - OCR runs instantly — The OCR engine reads the image. If no
langwas given, the script is auto-detected (Latin → eng, Devanagari → hin, and so on) and the matching language is applied automatically. - Get text + markdown back — The response contains the plain
text, the rebuiltmarkdown, character/word/line metrics, detected script, and processing time — all in one JSON body. One unit is deducted from your monthly quota only when the extraction succeeds.
One image per request. The endpoint processes a single image at a time. For batch workloads, send requests in parallel up to your plan’s per-minute rate limit.
Input modes — four ways to send an image
The API accepts the image in any of these formats. Use whichever fits your environment.
1. Direct file upload (multipart) — recommended
Upload the image as a multipart form field. The field name can be image, file, data, photo, img, upload, or attachment — all are accepted. Any common format works: JPG, PNG, WebP, GIF, BMP, TIFF, HEIC, AVIF.
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-F "image=@photo.jpg" 2. Public URL — image_url
Pass any public URL that returns image bytes. The image is validated by its actual content (MIME type), not by file extension — so URLs without an extension work too. For example, https://example.com/image that directly serves an image is accepted.
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d '{"image_url":"https://cdn.example.com/receipt.png"}' 3. Google Drive share link — image_url
Paste a Google Drive share link directly. The API automatically detects Drive links (/file/d/ID/view, open?id=, uc?id=) and fetches the file. Make sure the file is shared with “Anyone with the link can view.” Dropbox links are also normalized to direct download.
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d '{"image_url":"https://drive.google.com/file/d/1--EMd70IQHnLuVJXqXH...../view"}' 4. Base64-encoded image — image_base64
Send the image inline as base64. Useful when your client can’t perform multipart uploads (some no-code platforms). A data:image/png;base64,... prefix is accepted and stripped automatically.
IMG_B64=$(base64 -w0 photo.jpg)
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d "{\"image_base64\":\"$IMG_B64\"}" Smart input detection. The API does not require a specific Content-Type header — form-data, JSON, and query strings all work. The image is auto-detected from whatever field you send it in, and URLs are validated by sniffing the downloaded bytes rather than the extension.
Request parameters
Headers
| Header | Type | Description |
|---|---|---|
x-api-key Required |
String | Your API key. Send in request header. |
Image source (one of)
| Field | Type | Description |
|---|---|---|
image / file / photo Multipart |
File | Image file uploaded as multipart form data. Any of these field names work. |
image_url JSON/Form |
String | Public URL serving image bytes — including direct CDN links, extensionless image URLs, and Google Drive / Dropbox share URLs. |
image_base64 JSON/Form |
String | Base64-encoded image data. Supports raw base64 or data:image/png;base64,... prefix. |
Processing options
| Field | Type | Description |
|---|---|---|
lang Optional |
String | OCR language code or combination. Leave blank for auto-detect (recommended). Combine with + (e.g. eng+hin). See language list. |
Auto-detect is the default. If you omit lang, the engine detects the script from the image and picks the matching language. Pass lang only when you want to force a specific language — for example a French document (fra) where Latin-script auto-detect would default to eng.
Unsupported language = instant error. If you send a lang value that is not in the supported list, the request is rejected with INVALID_INPUT before authentication and before any quota is touched.
Code examples
Simple extraction (auto-detect language)
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-F "image=@photo.jpg" const form = new FormData();
form.append('image', fileInput.files[0]);
const res = await fetch('https://api.corenexis.com/image-ocr/v1', {
method: 'POST',
headers: { 'x-api-key': 'your_api_key' },
body: form
});
const data = await res.json();
console.log(data.data.text); import requests
with open("photo.jpg", "rb") as f:
res = requests.post(
"https://api.corenexis.com/image-ocr/v1",
headers={"x-api-key": "your_api_key"},
files={"image": f}
)
data = res.json()
print(data["data"]["text"]) $ch = curl_init("https://api.corenexis.com/image-ocr/v1");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["x-api-key: your_api_key"],
CURLOPT_POSTFIELDS => ["image" => new CURLFile("photo.jpg")],
]);
$resp = json_decode(curl_exec($ch), true);
echo $resp["data"]["text"]; Force a specific language
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-F "image=@notice.png" \
-F "lang=hin" curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-F "image=@bill.webp" \
-F "lang=eng+hin" import requests
with open("document.jpg", "rb") as f:
res = requests.post(
"https://api.corenexis.com/image-ocr/v1",
headers={"x-api-key": "your_api_key"},
files={"image": f},
data={"lang": "fra"}
)
print(res.json()["data"]["markdown"]) Image from URL / Google Drive
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d '{"image_url":"https://cdn.example.com/receipt.png","lang":""}' # URL has no .png/.jpg — detected by content, not extension
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d '{"image_url":"https://example.com/image"}' curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-d '{"image_url":"https://drive.google.com/file/d/1--EMd70IQHnLuVJXqXH...../view","lang":"eng+hin"}' curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-F "image_url=https://cdn.example.com/screenshot.png" Base64 image
IMG_B64=$(base64 -w0 photo.jpg)
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
-H "x-api-key: your_api_key" \
-H "Content-Type: application/json" \
-d "{\"image_base64\":\"$IMG_B64\"}" import requests, base64
with open("photo.jpg", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
res = requests.post(
"https://api.corenexis.com/image-ocr/v1",
headers={"x-api-key": "your_api_key"},
json={"image_base64": b64}
)
print(res.json()["data"]["text"]) Full extract + use result
import requests
API_KEY = "your_api_key"
with open("photo.jpg", "rb") as f:
res = requests.post(
"https://api.corenexis.com/image-ocr/v1",
headers={"x-api-key": API_KEY},
files={"image": f}
).json()
if not res["success"]:
raise SystemExit(res["message"])
d = res["data"]
print("Detected lang:", d["lang"], "| auto:", d["lang_auto_detected"])
print("Words:", d["metrics"]["word_count"])
print("---- TEXT ----")
print(d["text"])
print("---- MARKDOWN ----")
print(d["markdown"])
print("Remaining quota:", res["usage"]["remaining"]) const API_KEY = 'your_api_key';
const form = new FormData();
form.append('image', fileInput.files[0]);
const res = await fetch('https://api.corenexis.com/image-ocr/v1', {
method: 'POST',
headers: { 'x-api-key': API_KEY },
body: form
}).then(r => r.json());
if (!res.success) throw new Error(res.message);
const d = res.data;
console.log('Detected lang:', d.lang, '| auto:', d.lang_auto_detected);
console.log('Words:', d.metrics.word_count);
console.log(d.text);
console.log(d.markdown);
console.log('Remaining:', res.usage.remaining); Response format
Because the API is synchronous, the extracted text comes back in the same response — there is no status to poll. A successful call returns data.status = "completed" with the full OCR output.
Success response
{
"success": true,
"plan": "starter",
"data": {
"status": "completed",
"filename": "photo.jpg",
"file_size": "242.5 KB",
"image": { "width": 1280, "height": 720, "format": "jpeg" },
"lang": "eng",
"lang_auto_detected": true,
"metrics": {
"char_count": 1342,
"char_count_no_spaces": 1098,
"word_count": 233,
"line_count": 41
},
"text": "Plain OCR text exactly as read...",
"markdown": "## HEADING\n\nParagraph text rebuilt from wrapped lines..."
},
"usage": {
"remaining": 498,
"rate_limit": 20,
"monthly_limit": 500
}
} Response fields
| Field | Type | Description |
|---|---|---|
success |
Boolean | true when the image was processed successfully |
plan |
String | Your current plan slug (free, starter, pro, max) |
data.status |
String | Always completed on success |
data.filename |
String | Original uploaded / resolved filename |
data.file_size |
String | Human-readable image size (e.g. 242.5 KB) |
data.image |
Object | Detected width, height, and format |
data.lang |
String | Language actually used for OCR |
data.lang_auto_detected |
Boolean | true if auto-detected, false if you passed lang |
data.metrics.char_count |
Integer | Total characters (with spaces) |
data.metrics.word_count |
Integer | Word count |
data.metrics.line_count |
Integer | Line count |
data.text |
String | Plain OCR text, as-is |
data.markdown |
String | Markdown version — paragraphs rebuilt, caps lines promoted to headings |
usage.remaining |
Integer | Extractions remaining this billing period |
usage.rate_limit |
Integer | Max requests per minute on your plan |
usage.monthly_limit |
Integer | Total monthly extractions on your plan |
No expiry, no storage. The text is returned inline in the response — there are no temporary CDN URLs to download and nothing is stored on our side. Save the output from the response body directly.
Supported languages
Leave lang blank for automatic detection. To force a language, pass its code. Combine multiple codes with + for multilingual images (e.g. eng+hin, chi_sim+eng). Multilingual and non-English codes require Starter plan or higher.
| Code | Language | Code | Language |
|---|---|---|---|
eng |
English | hin |
Hindi |
ara |
Arabic | fra |
French |
deu |
German | spa |
Spanish |
por |
Portuguese | ita |
Italian |
rus |
Russian | chi_sim |
Chinese (Simplified) |
chi_tra |
Chinese (Traditional) | jpn |
Japanese |
kor |
Korean | ben |
Bengali |
urd |
Urdu | tam |
Tamil |
tel |
Telugu | mar |
Marathi |
guj |
Gujarati | kan |
Kannada |
mal |
Malayalam | pan |
Punjabi |
nld |
Dutch | pol |
Polish |
tur |
Turkish | vie |
Vietnamese |
tha |
Thai | ind |
Indonesian |
fas |
Persian (Farsi) | heb |
Hebrew |
How auto-detect picks a language
The image’s script is detected, then the matching language is applied automatically:
| Detected script | Language used |
|---|---|
| Latin | eng |
| Devanagari | hin |
| Arabic | ara |
| Han | chi_sim |
| Japanese | jpn |
| Korean | kor |
| Cyrillic | rus |
| Bengali / Tamil / Telugu / etc. | respective code |
Latin-script note. All Latin-based languages (English, French, German, Spanish, etc.) detect as “Latin” and default to eng. For a French or German image, pass lang=fra or lang=deu for better accuracy. Non-Latin scripts auto-detect correctly.
Error codes
Every error response is consistent JSON: { success: false, code: "...", message: "..." }. Many errors include extra fields (param, provided, max_allowed) to help you self-correct without contacting support.
HTTP status reference
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_INPUT |
Bad input — missing image, unsupported language code, or a file that is not a valid image. |
| 400 | PARAM_LIMIT_EXCEEDED |
Request exceeds your plan’s limit (image size or a feature). Includes param + max_allowed fields. |
| 400 | INVALID_BODY |
Request body is not valid JSON. |
| 401 | MISSING_KEY |
x-api-key header not present. |
| 401 | INVALID_KEY |
API key is invalid, expired, or not found. |
| 403 | KEY_DISABLED |
API key has been disabled. Generate a new one. |
| 403 | ACCOUNT_SUSPENDED |
Account suspended. Contact support. |
| 403 | ACCOUNT_INACTIVE |
Account not activated. Verify your email first. |
| 403 | EMAIL_NOT_VERIFIED |
Email address has not been verified. |
| 402 | NO_SUBSCRIPTION |
No active subscription on the Image OCR API. Subscribe first. |
| 402 | SUBSCRIPTION_EXPIRED |
Subscription expired. Renew to continue. |
| 402 | SUBSCRIPTION_CANCELLED |
Subscription cancelled. |
| 402 | SUBSCRIPTION_INACTIVE |
Subscription is inactive. |
| 402 | BILLING_REQUIRES_ACTION |
Billing requires action. Update payment method. |
| 404 | API_NOT_FOUND |
API slug not configured on the platform. |
| 429 | RATE_LIMIT_EXCEEDED |
Too many requests per minute. Wait 60 seconds. |
| 429 | QUOTA_EXCEEDED |
Monthly quota reached. Upgrade your plan or wait for renewal. |
| 502 | PROCESSING_FAILED |
Internal OCR service rejected or failed the request. Quota was not used. |
| 503 | API_UNAVAILABLE |
Service temporarily unavailable. Retry shortly. |
| 503 | AUTH_SERVICE_UNAVAILABLE |
Authentication backend is temporarily unreachable. Retry. |
Example error responses
{
"success": false,
"code": "PARAM_LIMIT_EXCEEDED",
"message": "Invalid value for 'max_file_size_bytes'. Allowed for your plan: 2097152 or less. Your request contains: 5242880. Please change 'max_file_size_bytes' or upgrade your plan.",
"param": "max_file_size_bytes",
"provided": 5242880,
"op": "lte",
"max_allowed": 2097152
} {
"success": false,
"code": "PARAM_LIMIT_EXCEEDED",
"message": "Feature 'lang' is not allowed on your current plan. Allowed for your plan: false. Your request contains: true. Please disable 'lang' or upgrade your plan.",
"param": "lang",
"provided": true,
"allowed": false
} {
"success": false,
"code": "INVALID_INPUT",
"message": "Unsupported language code 'klingon'. See the docs for the supported list."
} {
"success": false,
"code": "INVALID_INPUT",
"message": "The provided file is not a valid image.",
"detected_mime": "application/pdf"
} {
"success": false,
"code": "QUOTA_EXCEEDED",
"message": "Monthly quota reached. Upgrade your plan or wait for the next billing cycle."
} {
"success": false,
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please wait before making another request."
} Quota-safe errors. When a request is rejected because of plan limits (image size, feature flags), an unsupported language, or an upstream OCR failure — your monthly quota is not consumed. Only successful extractions count.
Rate limiting. Free 10/min · Starter 20/min · Pro 60/min · Max 60/min. Rejected requests still count toward your per-minute rate limit (anti-abuse) but never toward your monthly quota.
Ready to extract smarter?
Create your free account and start converting images to text and markdown in seconds. No credit card required.