New User Offer Get $5 free credit instantly — no credit card required. Use code WELCOME Claim $5 Free
API V1 — Production Ready

Image to Text & Markdown 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.

30+
Languages
50MB
Max Image Size
Instant
Synchronous Response
99.9%
Uptime SLA

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. Every plan includes the full OCR engine with text + markdown output — higher tiers unlock larger images and more monthly extractions.

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
Starter
$4.99/month
  • 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/month
  • 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 Started
Max
$29.99/month
  • 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
  • Dedicated support
  • Accelerated processing
Get Started
Enterprise

Enterprise & Agency Plan

High-volume image processing, custom retention, dedicated workers, and SLAs. We'll build a plan around your exact requirements.

Unlimited extractions
100+ MB images
Batch processing
Dedicated queue
24/7 Support

API Reference

Everything you need to integrate the Image 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 KeySign 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 designOne 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 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.

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.

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.

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 requestThe 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
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
  -H "x-api-key: your_api_key" \
  -F "[email protected]"

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

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

HeaderTypeDescription
x-api-keyRequiredStringYour API key. Send in request header.

Image Source (one of)

FieldTypeDescription
image / file / photoMultipartFileImage file uploaded as multipart form data. Any of these field names work.
image_urlJSON/FormStringPublic URL serving image bytes — including direct CDN links, extensionless image URLs, and Google Drive / Dropbox share URLs.
image_base64JSON/FormStringBase64-encoded image data. Supports raw base64 or data:image/png;base64,... prefix.

Processing Options

FieldTypeDescription
langOptionalStringOCR language code or combination. Leave blank for auto-detect (recommended). Combine with + (e.g. eng+hin). See language list.
Auto-detect is the defaultIf 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 errorIf 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 "[email protected]"
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 "[email protected]" \
  -F "lang=hin"
curl -X POST "https://api.corenexis.com/image-ocr/v1" \
  -H "x-api-key: your_api_key" \
  -F "[email protected]" \
  -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

FieldTypeDescription
successBooleantrue when the image was processed successfully
planStringYour current plan slug (free, starter, pro, max)
data.statusStringAlways completed on success
data.filenameStringOriginal uploaded / resolved filename
data.file_sizeStringHuman-readable image size (e.g. 242.5 KB)
data.imageObjectDetected width, height, and format
data.langStringLanguage actually used for OCR
data.lang_auto_detectedBooleantrue if auto-detected, false if you passed lang
data.metrics.char_countIntegerTotal characters (with spaces)
data.metrics.word_countIntegerWord count
data.metrics.line_countIntegerLine count
data.textStringPlain OCR text, as-is
data.markdownStringMarkdown version — paragraphs rebuilt, caps lines promoted to headings
usage.remainingIntegerExtractions remaining this billing period
usage.rate_limitIntegerMax requests per minute on your plan
usage.monthly_limitIntegerTotal monthly extractions on your plan
No expiry, no storageThe 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.

CodeLanguageCodeLanguage
engEnglishhinHindi
araArabicfraFrench
deuGermanspaSpanish
porPortugueseitaItalian
rusRussianchi_simChinese (Simplified)
chi_traChinese (Traditional)jpnJapanese
korKoreanbenBengali
urdUrdutamTamil
telTelugumarMarathi
gujGujaratikanKannada
malMalayalampanPunjabi
nldDutchpolPolish
turTurkishvieVietnamese
thaThaiindIndonesian
fasPersian (Farsi)hebHebrew

How auto-detect picks a language

The image's script is detected, then the matching language is applied automatically:

Detected ScriptLanguage used
Latineng
Devanagarihin
Arabicara
Hanchi_sim
Japanesejpn
Koreankor
Cyrillicrus
Bengali / Tamil / Telugu / etc.respective code
Latin-script noteAll 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

HTTPCodeDescription
400INVALID_INPUTBad input — missing image, unsupported language code, or a file that is not a valid image.
400PARAM_LIMIT_EXCEEDEDRequest exceeds your plan's limit (image size or a feature). Includes param + max_allowed fields.
400INVALID_BODYRequest body is not valid JSON.
401MISSING_KEYx-api-key header not present.
401INVALID_KEYAPI key is invalid, expired, or not found.
403KEY_DISABLEDAPI key has been disabled. Generate a new one.
403ACCOUNT_SUSPENDEDAccount suspended. Contact support.
403ACCOUNT_INACTIVEAccount not activated. Verify your email first.
403EMAIL_NOT_VERIFIEDEmail address has not been verified.
402NO_SUBSCRIPTIONNo active subscription on the Image OCR API. Subscribe first.
402SUBSCRIPTION_EXPIREDSubscription expired. Renew to continue.
402SUBSCRIPTION_CANCELLEDSubscription cancelled.
402SUBSCRIPTION_INACTIVESubscription is inactive.
402BILLING_REQUIRES_ACTIONBilling requires action. Update payment method.
404API_NOT_FOUNDAPI slug not configured on the platform.
429RATE_LIMIT_EXCEEDEDToo many requests per minute. Wait 60 seconds.
429QUOTA_EXCEEDEDMonthly quota reached. Upgrade your plan or wait for renewal.
502PROCESSING_FAILEDInternal OCR service rejected or failed the request. Quota was not used.
503API_UNAVAILABLEService temporarily unavailable. Retry shortly.
503AUTH_SERVICE_UNAVAILABLEAuthentication 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 ErrorsWhen 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 LimitingFree 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

Get the latest updates delivered straight to your inbox