Process Documents
Submit documents for OCR, check processing status, stream results, and download output in multiple formats.
| Endpoint | Description |
|---|---|
| POST v3/pdf | Submit a document for async OCR processing |
| GET v3/pdf/{pdf_id}/stream | Stream page results via SSE |
| GET v3/pdf/{pdf_id} | Check processing status |
| GET v3/converter/{pdf_id} | Check conversion format status |
| GET v3/pdf/{pdf_id}.{ext} | Download results in a specific format |
| DELETE v3/pdf/{pdf_id} | Permanently delete output data |
See the PDF processing guide for step-by-step examples.
POST v3/pdf
POST api.mathpix.com/v3/pdf
Process PDFs, ebooks, and documents asynchronously. Returns a pdf_id for polling status and downloading results. Maximum file size: 1 GB.
Supported inputs (full list):
- Documents: PDF, DOCX, PPTX, DOC, WPD, ODT
- Ebooks: EPUB, AZW/AZW3/KFX, MOBI, DJVU
Supported outputs (full list):
- Text: MMD, MD, HTML, LaTeX (.tex.zip)
- Office: DOCX, PPTX
- PDF: HTML-rendered or LaTeX-rendered
- Archives: ZIP variants with embedded images
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl -X POST https://api.mathpix.com/v3/pdf \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY' \
-H 'Content-Type: application/json' \
--data '{"url": "https://cdn.mathpix.com/examples/cs229-notes1.pdf", "conversion_formats": {"docx": true, "tex.zip": true}}'
import requests
r = requests.post("https://api.mathpix.com/v3/pdf",
json={
"url": "https://cdn.mathpix.com/examples/cs229-notes1.pdf",
"conversion_formats": {"docx": True, "tex.zip": True}
},
headers={
"app_id": "APP_ID",
"app_key": "APP_KEY",
"Content-type": "application/json"
}
)
print(r.json()) # {"pdf_id": "..."}
const response = await fetch("https://api.mathpix.com/v3/pdf", {
method: "POST",
headers: {
app_id: "APP_ID",
app_key: "APP_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://cdn.mathpix.com/examples/cs229-notes1.pdf",
conversion_formats: { docx: true, "tex.zip": true },
}),
});
const { pdf_id } = await response.json();
console.log(`PDF ID: ${pdf_id}`);
body := bytes.NewBufferString(`{
"url": "https://cdn.mathpix.com/examples/cs229-notes1.pdf",
"conversion_formats": {"docx": true, "tex.zip": true}
}`)
req, _ := http.NewRequest("POST", "https://api.mathpix.com/v3/pdf", body)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result)) // {"pdf_id": "..."}
HttpClient client = HttpClient.newHttpClient();
String body = """
{
"url": "https://cdn.mathpix.com/examples/cs229-notes1.pdf",
"conversion_formats": { "docx": true, "tex.zip": true }
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/pdf"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
{
"pdf_id": "2024_01_15_abc123def456"
}
Request parameters
You can either send a file URL in a JSON body, or upload a file via multipart form-data (with parameters in options_json).
url HTTP URL where the file can be downloaded from
streaming Whether streaming should be enabled for this request, see stream pdf pages.
metadata Key-value object. Supports improve_mathpix for extra privacy controls.
alphabets_allowed Specify which alphabets you don't want in the output
rm_spaces Determines whether extra white space is removed from equations in latex_styled and text formats.
rm_fonts Determines whether font commands such as \mathbf and \mathrm are removed from equations in latex_styled and text formats.
idiomatic_eqn_arrays Specifies whether to use aligned, gathered, or cases instead of an array environment for a list of equations.
include_equation_tags Specifies whether to include equation number tags inside equations LaTeX. When set to true, it sets "idiomatic_eqn_arrays": true, because equation numbering works better in those environments compared to the array environment.
Example
\tag{eq_number}, where eq_number is an equation number (e.g. 1.12)
include_smiles Enable experimental chemistry diagram OCR, via RDKIT normalized SMILES with isomericSmiles=False, included in text output format, via MMD SMILES syntax <smiles>...</smiles>.
include_chemistry_as_image Returns an image crop containing the SMILES in the alt-text for chemical diagrams.
Example

include_diagram_text Enables text extraction from diagrams. The extracted text will be part of lines.json data, and not part of the lines.mmd.json or final mmd. The parent_id of these text lines will correspond to the id of one of the diagrams in the lines.json data.
include_page_info Controls whether page info elements are included in the final MMD output. Page info refers to elements like headers, footers, and page numbers that are not part of the main text (unlike v3/text where it defaults to true).
numbers_default_to_math math_inline_delimiters Specifies begin inline math and end inline math delimiters for text outputs.
math_display_delimiters Specifies begin display math and end display math delimiters for text outputs.
page_ranges Specifies a page range as a comma-separated string.
Examples
2,4-6selects pages [2,4,5,6]2 - -2selects all pages starting with the second page and ending with the next-to-last page (specified by -2)
enable_spell_check Deprecated, has no effect on the output.
auto_number_sections Specifies whether sections and subsections in the output are automatically numbered note
remove_section_numbering Specifies whether to remove existing numbering for sections and subsections note
preserve_section_numbering Specifies whether to keep existing section numbering as is note
enable_tables_fallback Enables advanced table processing algorithm that supports large and complex tables.
fullwidth_punctuation Controls if punctuation will be fullwidth Unicode (default for east Asian languages like Chinese), or halfwidth Unicode (default for Latin scripts, Cyrillic scripts etc.). When null, fullwidth vs halfwidth will be decided based on image content. Punctuation inside math will always stay halfwidth.
conversion_formats Specifies formats that the v3/pdf output (Mathpix Markdown) should automatically be converted into on completion.
conversion_options Options for specific output formats (e.g. font, margins, orientation for DOCX).
Section numbering
Only one of auto_number_sections, remove_section_numbering, or preserve_section_numbering can be true at a time. The default behavior is to preserve section numbering (preserve_section_numbering set to true). Setting multiple flags returns error opts_section_numbering.
Response body
pdf_id Tracking ID to get status and result when completed
error US locale error message
error_info Error info object
GET v3/pdf/{pdf_id}/stream
Stream page results via server-sent events (SSE) for lower time to first data. Requires streaming: true in the initial POST request.
GET api.mathpix.com/v3/pdf/{pdf_id}/stream
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl -N https://api.mathpix.com/v3/pdf/PDF_ID/stream \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY' \
-H 'Accept: text/event-stream'
import requests
r = requests.get("https://api.mathpix.com/v3/pdf/PDF_ID/stream",
headers={
"app_id": "APP_ID",
"app_key": "APP_KEY",
"Accept": "text/event-stream"
},
stream=True
)
for line in r.iter_lines(decode_unicode=True):
if line.startswith("data: "):
print(line[6:])
const response = await fetch("https://api.mathpix.com/v3/pdf/PDF_ID/stream", {
headers: {
app_id: "APP_ID",
app_key: "APP_KEY",
Accept: "text/event-stream",
},
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
for (const line of chunk.split("\n")) {
if (line.startsWith("data: ")) console.log(line.slice(6));
}
}
req, _ := http.NewRequest("GET", "https://api.mathpix.com/v3/pdf/PDF_ID/stream", nil)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
req.Header.Set("Accept", "text/event-stream")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "data: ") {
fmt.Println(line[6:])
}
}
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/pdf/PDF_ID/stream"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.header("Accept", "text/event-stream")
.GET()
.build();
HttpResponse<Stream<String>> response = client.send(request,
HttpResponse.BodyHandlers.ofLines());
response.body()
.filter(line -> line.startsWith("data: "))
.forEach(line -> System.out.println(line.substring(6)));
text Mathpix Markdown output
page_idx page index from selected page range, starting at 1 and going all the way to pdf_selected_len
pdf_selected_len total number of pages inside selected page range
confidence overall confidence score for the page (0–1)
confidence_rate rate of high-confidence characters on the page (0–1)
version model version used for processing (e.g. SuperNet-109p4)
Pages are streamed one JSON object at a time. Pages are not guaranteed to be in order, although they generally will be.
GET v3/pdf/{pdf_id}
Check the processing status of a PDF.
GET api.mathpix.com/v3/pdf/{pdf_id}
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl https://api.mathpix.com/v3/pdf/PDF_ID \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY'
import requests
r = requests.get("https://api.mathpix.com/v3/pdf/PDF_ID",
headers={"app_id": "APP_ID", "app_key": "APP_KEY"}
)
print(r.json()) # {"status": "completed", "num_pages": 10, ...}
const response = await fetch("https://api.mathpix.com/v3/pdf/PDF_ID", {
headers: { app_id: "APP_ID", app_key: "APP_KEY" },
});
const status = await response.json();
console.log(status);
req, _ := http.NewRequest("GET", "https://api.mathpix.com/v3/pdf/PDF_ID", nil)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/pdf/PDF_ID"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
pdf_id The PDF tracking ID
status | Value | Meaning |
|---|---|
received | Request accepted |
loaded | PDF downloaded onto our servers |
split | Pages split and sent for processing |
completed | Processing finished successfully |
error | A problem occurred during processing |
num_pages Total number of pages in PDF document
num_pages_completed Current number of pages in PDF document that have been OCR-ed
percent_done Percentage of pages in PDF that have been OCR-ed
app_id The app ID that submitted the request
group_id The group ID associated with the request
input_file Original filename of the uploaded document
conversion_status Status of each requested conversion format.
GET v3/converter/{pdf_id}
Check the status of requested conversion formats.
GET api.mathpix.com/v3/converter/{pdf_id}
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl https://api.mathpix.com/v3/converter/PDF_ID \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY'
import requests
r = requests.get("https://api.mathpix.com/v3/converter/PDF_ID",
headers={"app_id": "APP_ID", "app_key": "APP_KEY"}
)
print(r.json()) # {"status": "completed", "conversion_status": {...}}
const response = await fetch("https://api.mathpix.com/v3/converter/PDF_ID", {
headers: { app_id: "APP_ID", app_key: "APP_KEY" },
});
const status = await response.json();
console.log(status);
req, _ := http.NewRequest("GET", "https://api.mathpix.com/v3/converter/PDF_ID", nil)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/converter/PDF_ID"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
status Always completed once the PDF has finished processing. Individual format progress is tracked in conversion_status.
conversion_status Status of each requested conversion format.
GET v3/pdf/{pdf_id}.{ext}
Download results by appending the format extension to the pdf_id. Results are available once status=completed. Conversion formats (e.g., docx) require the format's conversion status to be completed.
GET api.mathpix.com/v3/pdf/{pdf_id}.{ext}
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl https://api.mathpix.com/v3/pdf/PDF_ID.docx \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY' \
-o output.docx
import requests
r = requests.get("https://api.mathpix.com/v3/pdf/PDF_ID.docx",
headers={"app_id": "APP_ID", "app_key": "APP_KEY"}
)
with open("output.docx", "wb") as f:
f.write(r.content)
import { writeFile } from "fs/promises";
const response = await fetch("https://api.mathpix.com/v3/pdf/PDF_ID.docx", {
headers: { app_id: "APP_ID", app_key: "APP_KEY" },
});
const buffer = await response.arrayBuffer();
await writeFile("output.docx", Buffer.from(buffer));
req, _ := http.NewRequest("GET", "https://api.mathpix.com/v3/pdf/PDF_ID.docx", nil)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
out, _ := os.Create("output.docx")
defer out.Close()
io.Copy(out, resp.Body)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/pdf/PDF_ID.docx"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.GET()
.build();
HttpResponse<Path> response = client.send(request,
HttpResponse.BodyHandlers.ofFile(Path.of("output.docx")));
System.out.println("Saved to " + response.body());
Accepted extensions: .mmd, .md, .docx, .tex.zip, .html, .pdf, .latex.pdf, .pptx, .mmd.zip, .md.zip, .html.zip, .lines.json, .lines.mmd.json
See Conversion Formats for availability and descriptions. The lines.json and lines.mmd.json extensions are v3/pdf-only — see PDF lines data and PDF MMD lines data.
PDF lines data
Detailed line-by-line data for PDFs, useful for building custom experiences on top of original PDFs.
Response data object
pages List of PdfPageData objects
PdfPageData object
image-id PDF ID, plus hyphen, plus page number, starting at page 1
page Page number
lines List of LineData objects
page_height Page height (in pixel coordinates)
page_width Page width (in pixel coordinates)
PdfLineData object
id Unique line identifier
parent_id Unique line identifier of the parent.
children_ids List of children unique identifiers.
type See line types and subtypes for details.
subtype See line types and subtypes for details.
line Line number
text Searchable text, empty string for page elements that do not necessarily have associated text (for example individual equations inside block of math equations).
text_display Mathpix Markdown content with contextual elements such as article, section and inline image URLs. Can be empty for page elements that will not render (for example page number, auxiliary text in the page header, etc.).
conversion_output When true, text_display from the line is included in the final MMD output, otherwise excluded.
is_printed True if line contains printed text, false otherwise.
is_handwritten True if line contains handwritten text, false otherwise.
region Bounding box of the line in pixel coordinates
cnt Specifies the image area as list of (x,y) pixel coordinate pairs. This captures handwritten content much better than a region object
confidence Estimated probability 100% correct (product of per token OCR confidence).
confidence_rate Estimated confidence of output quality (geometric mean of per token OCR confidence).
PDF MMD lines data (deprecated)
Deprecated. Use lines.json instead, which contains all this information and more.
Response data object (MMD Lines)
pages List of PdfMMDPageData objects
PdfMMDPageData object
image-id PDF ID, plus hyphen, plus page number, starting at page 1
page Page number
lines List of PageMMDLineData objects
page_height Page height (in pixel coordinates)
page_width Page width (in pixel coordinates)
PdfMMDLineData object
line Line number
text Mathpix Markdown content with contextual elements such as article, section and inline image URLs
is_printed True if line contains printed text, false otherwise.
is_handwritten True if line contains handwritten text, false otherwise.
region Bounding box of the line in pixel coordinates
cnt Specifies the image area as list of (x,y) pixel coordinate pairs. This captures handwritten content much better than a region object
confidence Estimated probability 100% correct (product of per token OCR confidence).
confidence_rate Estimated confidence of output quality (geometric mean of per token OCR confidence).
DELETE v3/pdf/{pdf_id}
Permanently delete a PDF's output data.
DELETE api.mathpix.com/v3/pdf/{pdf_id}
Example
- cURL
- Python
- JavaScript / TypeScript
- Go
- Java
curl -X DELETE https://api.mathpix.com/v3/pdf/PDF_ID \
-H 'app_id: APP_ID' \
-H 'app_key: APP_KEY'
import requests
r = requests.delete("https://api.mathpix.com/v3/pdf/PDF_ID",
headers={"app_id": "APP_ID", "app_key": "APP_KEY"}
)
print(r.json())
const response = await fetch("https://api.mathpix.com/v3/pdf/PDF_ID", {
method: "DELETE",
headers: { app_id: "APP_ID", app_key: "APP_KEY" },
});
console.log(response.status);
req, _ := http.NewRequest("DELETE", "https://api.mathpix.com/v3/pdf/PDF_ID", nil)
req.Header.Set("app_id", "APP_ID")
req.Header.Set("app_key", "APP_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
result, _ := io.ReadAll(resp.Body)
fmt.Println(string(result))
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.mathpix.com/v3/pdf/PDF_ID"))
.header("app_id", "APP_ID")
.header("app_key", "APP_KEY")
.DELETE()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
When a PDF is deleted:
- All output files are permanently removed from our servers (MMD, images, JSON Lines, and all requested formats)
- The original input file is also deleted
- This deletion is permanent and cannot be undone
Download and store files locally before deleting if you need to keep them.
PDF page images and cropped images (figures, diagrams) served via CDN may remain accessible for up to 24 hours after deletion while cached copies expire.
Minimal metadata is retained for auditing and billing: status, input_file name, num_pages, timestamps, and processing version. No output content is stored.
If privacy is a concern, rename the file before upload to avoid storing identifiable filenames.
Response body
Returns the PDF status object at the time of deletion.
pdf_id The PDF tracking ID
app_id The app ID that submitted the request
group_id The group ID associated with the request
status Processing status at time of deletion (e.g. completed)
input_file Original filename of the uploaded document
num_pages Total number of pages in PDF document
num_pages_completed Number of pages that were OCR-ed
percent_done Percentage of pages that were OCR-ed
conversion_status Status of each requested conversion format
After deletion, subsequent GET requests to v3/pdf/{pdf_id} return the same status object with an additional deleted_at field:
deleted_at ISO 8601 timestamp of when the PDF was deleted. Only present on GET requests after deletion.