Skip to content

OCR API

POST /api/v1/ocr/extract — extract text from images and documents as Markdown, powered by Cloudflare Workers AI.

Extract text from an image or document and return the content as Markdown. Powered by Cloudflare Workers AI's native document-to-markdown conversion.

POST/api/v1/ocr/extract

Authenticate with an LLM API key (sk-ar-v1-…) from /dashboard/keys, sent as Authorization: Bearer …. Management keys (ak_…) are not accepted.

Request

The endpoint accepts two content types: a JSON body with a base64 image, or a multipart file upload.

FieldTypeRequiredDescription
imagestringyes (JSON only)Base64-encoded image bytes, or a data URL (data:<mime>;base64,<data>).
filenamestringno (JSON only)Optional filename hint. Helps the extractor detect the file type. 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

The endpoint accepts any image or document format that Cloudflare Workers AI's toMarkdown conversion supports, including PNG, JPEG, GIF, WebP, BMP, TIFF, and PDF.

The maximum accepted file size is 5 MiB. Requests that exceed this limit receive a 413 response.

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
}
FieldTypeDescription
textstringExtracted content in Markdown format.
formatstringAlways "markdown".
modelstringAlways "cloudflare/ai-to-markdown".
tokensnumberToken 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

StatusCodeDescription
400missing_required_fieldsThe image field is absent or empty.
400invalid_request_bodyThe request body is not valid JSON or is not parseable multipart.
400invalid_image_encodingThe image value is not valid base64 or a valid data URL.
400invalid_image_fieldThe multipart image field is a string, not a file.
401invalid_api_keyThe API key is missing, expired, or invalid.
413image_too_largeThe image exceeds the 5 MiB limit.
500missing_workers_ai_bindingThe Workers AI binding is not configured (server misconfiguration).
502ocr_upstream_failedThe extraction call failed. Retry the request.
502ocr_extraction_errorWorkers AI returned an error for this file (for example: unsupported format or corrupt data).

See Errors for retry guidance.

  • Embeddings — vectors for search and RAG
  • Models — list and inspect every supported model