DocsOpen Moon AI
Browse the docs

OCR (document text)

Reference for POST /v1/ocr: extract the text of a PDF or an image with moon-ocr-1, which runs on our servers in France and sends nothing to a provider.

On this page

POST /v1/ocr returns the text of a PDF or an image, page by page, in Markdown. A page that already has a text layer (a PDF exported from a word processor) is read directly; a scanned page or a photo is read by optical character recognition.

HTTP
POST https://api.realmoon.ai/v1/ocr
  • Authentication: an sk-moon-… key with the inference scope (see Authentication).
  • Body: multipart/form-data (with the Content-Length header) or JSON, in the shape of the Mistral OCR API.
  • Response: the text of each page read.

The only model is moon-ocr-1. It runs on our servers in France: the document is not sent to any provider and is not kept once the response is returned.

ParametersLink to the Parameters section

MultipartLink to the Multipart section

FieldTypeRequiredDescription
file (or document)fileyesThe PDF or the image (PNG, JPEG, WebP, GIF), 30 MB at most. A single file.
modelstringnomoon-ocr-1 (default).
pagesstringnoThe pages to read, numbered from 0 and separated by commas: 0,2,5.

JSONLink to the JSON section

ParameterTypeRequiredDescription
documentobject or stringyes{"type": "document_url", "document_url": "data:application/pdf;base64,..."} or {"type": "image_url", "image_url": "data:image/png;base64,..."}. A bare string (data: URL or base64) is also accepted.
modelstringnomoon-ocr-1 (default).
pagesarray of integersnoThe pages to read, starting from 0.
include_image_base64booleannoOnly false is accepted: page images are not returned.
idstringnoAccepted, with no effect.

In JSON, any other parameter is rejected with 400 unknown_parameter.

PagesLink to the Pages section

  • Without pages, the whole document is read, up to 50 pages. Beyond that, the API responds with 400 too_many_pages: choose the pages, and split a long document across several requests.
  • An image has a single page, page 0.
  • A page requested more than once is read only once.

ExampleLink to the Example section

The OpenAI SDKs have no method for this endpoint: call it over HTTP.

cURL
curl https://api.realmoon.ai/v1/ocr \
  -H "Authorization: Bearer $MOONAI_API_KEY" \
  -F model=moon-ocr-1 \
  -F file=@invoice.pdf \
  -F pages=0,1
Python
import os
import requests

with open("invoice.pdf", "rb") as document:
    response = requests.post(
        "https://api.realmoon.ai/v1/ocr",
        headers={"Authorization": f"Bearer {os.environ['MOONAI_API_KEY']}"},
        data={"model": "moon-ocr-1", "pages": "0,1"},
        files={"file": ("invoice.pdf", document, "application/pdf")},
        timeout=100,
    )
response.raise_for_status()
for page in response.json()["pages"]:
    print(page["index"], page["source"])
    print(page["markdown"])
JavaScript
import fs from 'node:fs';

const form = new FormData();
form.append('model', 'moon-ocr-1');
form.append('pages', '0,1');
form.append('file', new Blob([fs.readFileSync('invoice.pdf')], { type: 'application/pdf' }), 'invoice.pdf');

const response = await fetch('https://api.realmoon.ai/v1/ocr', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.MOONAI_API_KEY}` },
  body: form,
});
const result = await response.json();
for (const page of result.pages) console.log(page.index, page.source, page.markdown);

The same call in JSON, with the document in base64:

JSON body
curl https://api.realmoon.ai/v1/ocr \
  -H "Authorization: Bearer $MOONAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\": \"moon-ocr-1\", \"document\": {\"type\": \"document_url\", \"document_url\": \"data:application/pdf;base64,$(base64 -w0 invoice.pdf)\"}, \"pages\": [0, 1]}"

ResponseLink to the Response section

Response
{
  "model": "moon-ocr-1",
  "pages": [
    {
      "index": 0,
      "markdown": "# Invoice No. 2026-118\n\nDate: November 4, 2026\n\n| Item | Amount |\n| --- | --- |\n| Services | €1,200.00 |",
      "source": "text",
      "images": [],
      "dimensions": null
    },
    {
      "index": 1,
      "markdown": "Payment terms: 30 days.",
      "source": "ocr",
      "images": [],
      "dimensions": null
    }
  ],
  "usage_info": { "pages_processed": 2, "doc_size_bytes": 184320 },
  "usage": { "pages": 2, "pages_not_read": 0, "credits": 0 }
}

The credits value is made up.

FieldTypeDescription
modelstringAlways moon-ocr-1.
pages[].indexintegerThe page number, starting from 0.
pages[].markdownstringThe page’s text, in Markdown.
pages[].sourcestringtext: read from the PDF’s text layer. ocr: read by character recognition.
pages[].images, pages[].dimensionsarray, nullAlways [] and null, kept for compatibility with the Mistral shape.
usage_info.pages_processed, usage_info.doc_size_bytesintegerPages read and document size in bytes, as in the Mistral API.
usage.pagesintegerPages read and billed.
usage.pages_not_readintegerRequested pages the request ran out of time to read. They are neither returned nor billed.
usage.creditsintegerCredits charged.
HeaderValue
X-Moon-Hostingfr: document read on our servers in France.
X-Moon-Blurnot_needed: the document never leaves our servers, so Moon Blur is not needed.
X-Moon-Request-Id, X-Moon-Prompt-StorageAs for any request.

CostsLink to the Costs section

The price is fixed per page read; it appears in GET /v1/models?type=ocr (pricing.credits_per_unit, billing: flat) and in the “Models” tab of the portal. The request holds the price of the requested pages, then charges only for the pages actually read. An unreadable document or a request that fails costs nothing.

LimitsLink to the Limits section

LimitValue
Document size30 MB
Pages per request50
Request durationAbout 85 seconds; pages not read in time are neither returned nor billed
Requests in flight per workspace2

The reading service is shared: when other requests keep it busy, the API responds with 429 too_many_concurrent or 503 ocr_busy. For a large document, send a few pages at a time and run the requests one after another.

ErrorsLink to the Errors section

HTTPcodeMeaning
400missing_required_parameterThe file or document is missing.
400unknown_parameterUnknown parameter (in JSON).
400unsupported_parameterinclude_image_base64 set to true.
400url_not_supportedDocument given as an https:// URL.
400unsupported_formatNeither a PDF nor a PNG, JPEG, WebP or GIF image.
400invalid_imageUnreadable image, or more than 40 megapixels.
400encrypted_documentPassword-protected PDF.
400invalid_documentPDF with no pages.
400too_many_pagesMore than 50 pages without pages.
400nullA page number that does not exist, a page other than 0 for an image, an empty document, invalid base64 (param names it).
403org_policyYour organization’s rules refuse the API or this model.
404model_not_foundA model other than moon-ocr-1.
411length_requiredMultipart upload without a Content-Length header.
413file_too_large, request_too_largeDocument larger than 30 MB.
422unreadable_documentThe document is unreadable or too heavy to read.
429too_many_concurrentToo many OCR requests in flight for this workspace, or for the service.
503ocr_busyThe reading service is busy: retry after Retry-After (10 seconds).
504ocr_timeoutReading took too long: send fewer pages.

Key, balance and spend cap errors are in Errors.

See alsoLink to the See also section

  • Privacy: what Moon AI keeps, and does not keep, from a document.
  • Models: the max_pages and max_file_mb fields.

Moon AI

Moon AI in action

0:00

Explore

Screenshots of chat.realmoon.ai taken on October 29, 2026, with fictional data.

Moon AI

Your preferences

Visits counted without cookies.

Our server counts visits without cookies or trackers. Your theme and your answer about ad measurement are remembered on this device.

Ad measurement

With your consent, our ad networks’ trackers (Google) measure our ads, from the visit to the sign-up and then to the first subscription and its amount, and may show you our ads. Your answer is valid for 13 months; you can change it here at any time.

No answer saved on this device.

After you decline, no tag is loaded anymore and the site deletes the cookies they had set on realmoon.ai. Those on the ad networks’ own domains are managed with them or in your browser.

The Moon AI app has its own privacy settings.