Quote before converting
POST /v1/quote tells you what converting each file would cost. It is a dry run: nothing is converted, no OCR model is called, no credits are reserved or charged, and it does not count toward the concurrent conversion limit. Authentication is the same as for /v1/convert.
curl -X POST https://api.md.tlelabs.com/v1/quote \ -H "Authorization: Bearer <YOUR_API_KEY>" \ -F "file=@a.pdf" -F "file=@b.docx" \ -F "ocr_model=openparser/mistral-ocr-4"Request
Section titled “Request”Content-Type: multipart/form-data:
| Field | Required | Value |
|---|---|---|
file |
yes | 1 to 10 files (repeat the field), priced in the order sent. |
ocr |
no | auto (default), force or off, as for /v1/convert; applies to every file. |
ocr_model |
no | auto (default) or a model id, as for /v1/convert; applies to every file. |
The whole request may be up to 50 MB (413 file_too_large). No file, more than 10 files (details: {"field": "file", "max": 10}) or an invalid ocr / ocr_model gets 400 invalid_request.
Response
Section titled “Response”200 OK. Example: a.pdf has 5 pages, 4 with a text layer and 1 scan; the second file is not a supported format.
{ "ocr": "auto", "ocr_model": "auto", "ocr_page_credits": 3, "files": [ { "index": 0, "filename": "a.pdf", "size_bytes": 81234, "status": "ok", "format": "pdf", "pages": 5, "text_pages": 4, "ocr_pages": 1, "details": { "estimate": "exact_if_ocr_succeeds", "pdf_pages": { "blank": 0, "text": 4, "scan": 1, "text_render": 0, "render": 0 }, "images_to_ocr": 1 }, "ocr_models": { "image": "novita/deepseek-ocr-2", "pdf": "openparser/paddleocr-vl-1.6" }, "credits": { "estimated": 7, "max": 15 }, "warnings": [] }, { "index": 1, "filename": "x.zip", "size_bytes": 120, "status": "error", "error": { "code": "unsupported_format", "message": "File format not recognized. Supported: HTML, DOCX, PDF, PPTX, XLSX." } } ], "total": { "files": 2, "ok": 1, "estimated_credits": 7, "max_credits": 15 }}| Field | Meaning |
|---|---|
pages, text_pages, ocr_pages |
Billed pages (how pages are counted); text_pages = pages − ocr_pages. |
credits.estimated |
text_pages × 1 + ocr_pages × ocr_page_credits: the price if every expected OCR succeeds. |
credits.max |
Exactly what /v1/convert would reserve for this file; you need this much available. |
details.estimate |
exact_if_ocr_succeeds: /v1/convert charges estimated when every OCR succeeds (less when some fail). upper_bound: the file could not be analyzed in detail, estimated = max. |
details.pdf_pages |
PDF: pages by kind — blank, text, scan, text_render (text layer plus a rendered read), render; null when not analyzed. |
details.images_to_ocr |
Pictures expected to be sent to OCR. |
details.basis |
HTML: "bytes" — priced by file size, like the reservation. |
ocr_models |
The model tried first for pictures and for PDF pages; null when there is none, with ocr=off, and pdf for non-PDF files. |
total |
Number of files, files ok, and the sums of estimated and max over the ok files. |
How each format is estimated
Section titled “How each format is estimated”- PDF up to 20 MB (in a request up to 20 MB): pages are classified with the same logic as
/v1/convert, so the estimate is exact when OCR succeeds. - PDF up to 20 MB in a request over 20 MB, with OCR on: not analyzed (
upper_bound,estimated = max, warningpage analysis skipped: request larger than 20 MB); quote that file alone for a detailed price. Withocr=offit is still counted exactly. - PDF over 20 MB: too large for OCR, so it is priced from its text layer (
ocr_pages0). Withocr=autoa page without text, and withocr=forceany file, getsfile_too_large, like/v1/convert; withocr=offit is priced from the text layer whatever it contains. - DOCX, PPTX, XLSX:
ocr_pagescounts the chunks, slides or sheets with a picture to OCR (estimated = maxwhen an image OCR model is available). Without one,ocr_pagesis 0,estimatedcan be lower thanmaxand a warning says pictures will not be read. - HTML:
estimated = max(upper_bound,basis: "bytes").
Errors per file
Section titled “Errors per file”A file that cannot be priced gets status: "error" with the same code and message /v1/convert would return — unsupported_format, file_too_large, page_limit_exceeded, image_limit_exceeded, parse_failed — or internal_error. It does not fail the request (still 200) and is not counted in total.