API v1 · Production ready

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.

Get started free Documentation POST https://api.corenexis.com/image-ocr/v1
30+Languages
50MBMax image size
InstantSynchronous response
99.9%Uptime SLA
Features

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.

Pricing

Simple, transparent pricing

Start free and scale as you grow. No hidden fees.

Free
Free
  • 50 extractions/month
  • 10 requests/minute
  • Up to 2 MB image size
  • Auto language detection
  • English OCR (eng)
  • Plain text + markdown output
Start Free
Most popular
Starter
$4.99 /mo
  • 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
Get Started
Pro
$14.99 /mo
  • 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
Get Pro
Max
$29.99 /mo
  • 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
Get Max
Agency
Custom
  • 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
Contact Sales
Documentation

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.

Header
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.

  1. Send the image — Send a POST request to /image-ocr/v1 with the image (file upload, URL, or base64) and an optional lang. The API reads the image, detects its MIME type, and measures its size.
  2. Validation against your plan — Your API key, subscription, rate limit, and image size are checked against your plan. If lang is provided but unsupported, the request is rejected immediately — before any processing or quota check.
  3. OCR runs instantly — The OCR engine reads the image. If no lang was given, the script is auto-detected (Latin → eng, Devanagari → hin, and so on) and the matching language is applied automatically.
  4. Get text + markdown back — The response contains the plain text, the rebuilt markdown, 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.

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
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
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"}'

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
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.

cURL
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

POST /image-ocr/v1
{
  "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.

Stay in the loop

New APIs, features and offers, straight to your inbox. No spam.

Already subscribed? Manage preferences