Mistral's OCR API
On this page
Updated November 2, 2026 — OCR. OCR 4.0 (
mistral-ocr-4-0) was retired on September 30, 2026. Use OCR 4.1 (mistral-ocr-4-1), which has been generally available since August 31 at the same price, or the aliasmistral-ocr-latest, which has pointed to it since July 16. OCR 4.1 adds confidence scores at the block level. Addendum November 3, 2026: To send a local PDF, encode it in base64 as{"type": "document_url", "document_url": "data:application/pdf;base64,…"}. Thedocument_base64type found in older examples does not exist in the documentation or themistralaiSDK, and those examples would have failed. Sources: OCR Processor · Document QnA.
A single entry point
All document extraction goes through a single endpoint: /v1/ocr, or its equivalent in the Python SDK, client.ocr.process(). Whether you are processing a photo of a receipt or an 800-page annual report, the call is the same. This lesson details how to configure it, the three ways to pass a document to it, and what it returns.
Installation and configuration
Installation takes a single command:
pip install mistralai
Next, instantiate the client with your API key:
from mistralai.client import Mistral
client = Mistral(api_key="your-api-key")
This approach works for a quick test in a notebook, but it risks accidentally committing your key. As soon as code leaves your machine, use an environment variable:
export MISTRAL_API_KEY="your-api-key"
import os
from mistralai.client import Mistral
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
We will use this second form in all subsequent lessons.
Call parameters
The client.ocr.process() call requires only two parameters: model, always set to "mistral-ocr-latest", and document, which describes the file to process in one of the three forms detailed below.
Other parameters adjust the output to your needs:
table_format: Table format (null,"markdown","html")include_image_base64:Trueto receive images in base64bbox_annotation_format: Bounding box annotation schemadocument_annotation_format: Full document annotation schemadocument_annotation_prompt: High-level instructions for annotation
The first two concern OCR proper, and you will handle them in the next lessons. The last three relate to annotations, covered starting in Lesson 9; for now, just remember that they let you request structured extraction in the same call, without a second round trip.
Three ways to send a document
The first, a public URL, is the most direct when the file is already accessible online—a published report, an attachment stored on a public bucket:
ocr_response = client.ocr.process(
model="mistral-ocr-latest",
document={
"type": "document_url",
"document_url": "https://example.com/document.pdf"
}
)
The second is necessary for documents that live on your machine or in private storage. You encode them in base64 and send them in the request body. This is the default method for anything confidential, since no URL needs to be exposed:
import base64
with open("my_document.pdf", "rb") as f:
document_base64 = base64.b64encode(f.read()).decode("utf-8")
ocr_response = client.ocr.process(
model="mistral-ocr-latest",
document={
"type": "document_url",
"document_url": f"data:application/pdf;base64,{document_base64}"
}
)
The third uses the Files API. You upload the file once, retrieve an ID, and then reference it in your calls. The benefit shows up with large documents, or when the same file must be processed multiple times—an OCR extraction today, an annotation with a different schema tomorrow: you do not retransfer 40 MB on every attempt.
# Upload the file
uploaded_file = client.files.upload(
file=open("my_document.pdf", "rb"),
purpose="ocr"
)
# Use the uploaded file
ocr_response = client.ocr.process(
model="mistral-ocr-latest",
document={
"type": "file_id",
"file_id": uploaded_file.id
}
)
Reading the response
The response exposes a list of pages, and each page carries its content along with its metadata. A minimal loop is enough to verify that extraction went smoothly:
for page in ocr_response.pages:
print(f"Page {page.index}")
print(f"Content: {page.markdown[:200]}...")
print(f"Images: {len(page.images)} found")
print(f"Header: {page.header}")
print(f"Footer: {page.footer}")
print(f"Dimensions: {page.dimensions}")
Make it a habit to run this kind of loop on a sample document before industrializing anything: it tells you in three seconds whether the page count matches, whether images were detected, and whether headers are properly isolated from the body text.
Limits and errors
Three constraints govern usage: 50 MB per file maximum, 1,000 pages per document, and input formats PDF, PNG, JPEG, AVIF, PPTX, and DOCX. On top of that comes rate limiting, with a threshold that depends on your subscription tier—a point to check before massive parallelization, or you risk seeing your calls rejected in a burst.
These limits, like network incidents, manifest as exceptions that you must catch. A batch job that stops at invoice number 300 because one file exceeds the allowed size is an avoidable waste of time:
from mistralai.client import Mistral
from mistralai.client.errors import SDKError
client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
try:
ocr_response = client.ocr.process(
model="mistral-ocr-latest",
document={
"type": "document_url",
"document_url": "https://example.com/document.pdf"
}
)
except SDKError as e:
print(f"API Error: {e.status_code} - {e.message}")
except Exception as e:
print(f"Unexpected error: {e}")
Distinguishing the two exception levels is useful: SDKError gives you a status code on which to decide whether to retry—a 429 should be retried after a delay, a 400 never—while the generic block catches local problems, such as a missing file or impossible encoding.
Key takeaways
- The OCR endpoint is
client.ocr.process()with the modelmistral-ocr-latest - Three sending methods: public URL, base64, uploaded file
- Optional parameters control table format and image inclusion
- The response is structured page by page with Markdown, images, and metadata
- Respect the limits of 50 MB and 1,000 pages per document