OCR API
POST /api/v1/ocr/extract extracts text from images and documents as Markdown.
Extract text from an image or document as Markdown, using Cloudflare Workers AI's document-to-markdown conversion.
Send an LLM API key (sk-ar-v1-…) from /dashboard/keys as Authorization: Bearer …. Management keys (ak_…) are not accepted.
Request
Send a JSON body with a base64 image, or a multipart file upload.
| Field | Type | Required | Description |
|---|---|---|---|
image | string | yes (JSON only) | Base64-encoded image bytes, or a data URL (data:<mime>;base64,<data>). |
filename | string | no (JSON only) | Filename hint for file-type detection. Defaults to image.png when not set. |
For multipart/form-data, include the file in a field named image. The filename is taken from the Content-Disposition header.
Supported formats
Any format Workers AI toMarkdown supports, including PNG, JPEG, GIF, WebP, BMP, TIFF, and PDF.
Maximum file size is 5 MiB; larger requests get 413.
Response
{
"text": "# Invoice #1042\n\n**Date:** 2026-06-15 \n**Amount:** $120.00\n\n## Line items\n\n| Description | Price |\n|---|---|\n| API credits | $120.00 |",
"format": "markdown",
"model": "cloudflare/ai-to-markdown",
"tokens": 68
}| Field | Type | Description |
|---|---|---|
text | string | Extracted content in Markdown format. |
format | string | Always "markdown". |
model | string | Always "cloudflare/ai-to-markdown". |
tokens | number | Token count consumed by the extraction. |
Examples
# JSON — base64 data URL
curl https://anyrouter.dev/api/v1/ocr/extract \
-H "Authorization: Bearer $ANYROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"image\": \"$(base64 -i receipt.png | tr -d '\n')\"}"
# Multipart — raw file upload
curl https://anyrouter.dev/api/v1/ocr/extract \
-H "Authorization: Bearer $ANYROUTER_API_KEY" \
-F "image=@receipt.png"// JSON path — base64 encode the image first
async function extractText(imageBuffer: ArrayBuffer): Promise<string> {
const base64 = btoa(String.fromCharCode(...new Uint8Array(imageBuffer)))
const response = await fetch("https://anyrouter.dev/api/v1/ocr/extract", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ANYROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
image: `data:image/png;base64,${base64}`,
filename: "document.png",
}),
})
const result = await response.json()
return result.text
}
// Multipart path — stream the file directly
async function extractTextFromFile(filePath: string): Promise<string> {
const { createReadStream } = await import("node:fs")
const form = new FormData()
form.append("image", new Blob([createReadStream(filePath)]), "document.png")
const response = await fetch("https://anyrouter.dev/api/v1/ocr/extract", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.ANYROUTER_API_KEY}` },
body: form,
})
const result = await response.json()
return result.text
}Errors
| Status | Code | Description |
|---|---|---|
| 400 | missing_required_fields | The image field is absent or empty. |
| 400 | invalid_request_body | The request body is not valid JSON or is not parseable multipart. |
| 400 | invalid_image_encoding | The image value is not valid base64 or a valid data URL. |
| 400 | invalid_image_field | The multipart image field is a string, not a file. |
| 401 | invalid_api_key | The API key is missing, expired, or invalid. |
| 413 | image_too_large | The image exceeds the 5 MiB limit. |
| 500 | missing_workers_ai_binding | The Workers AI binding is not configured (server misconfiguration). |
| 502 | ocr_upstream_failed | The extraction call failed. Retry the request. |
| 502 | ocr_extraction_error | Workers AI returned an error for this file (for example: unsupported format or corrupt data). |
See Errors for retry guidance.
AnyRouter routes requests to third-party models. Models and outputs are provided as is, with no warranty; you use them at your own risk. Disclaimer