V1 HTTP API Walkthrough
The self-hosted V1 API is the same interface the Python SDK and WebUI use. This page explains the request cycle — create an upload, upload the bytes, submit a parse job, poll to a terminal state, download the outputs — and points to a tested example script. For the Python client, see Python SDK.
Start a local service, or point the examples at any V1 deployment including the official cloud service:
mineru-kit api-server --host 127.0.0.1 --port 8000 --tier standard
Tested example script
The complete cycle — including timeouts, response validation, bounded polling, exit codes, and credential isolation — is maintained as a single tested script in the repository:
export MINERU_API_URL=http://127.0.0.1:8000
export MINERU_API_KEY=secret-key # omit for anonymous local access
./scripts/http_api_example.sh document.pdf
The script's behavior is verified by tests/unittest/test_http_api_example_script.py against a real Flash service and a scripted mock, without model downloads. Exit codes are stable for automation:
| Code | Meaning |
|---|---|
0 |
Job completed; every requested artifact was saved |
1 |
Script, transport, protocol, download, or local write failure |
2 |
Job partial: artifacts of completed files were saved first |
3 |
Job failed |
4 |
Job canceled |
124 |
Polling budget exhausted; job_id printed so polling can resume |
Authentication and the byte upload
Requests to /v1/* carry Authorization: Bearer $MINERU_API_KEY when the service is started with --api-key; omit the header for anonymous local access.
The byte upload uses exactly the method, URL, and headers returned by POST /v1/uploads:
- A self-hosted service returns a same-origin URL such as
/v1/uploads/{id}/content. Same-origin means scheme + host + effective port; it is checked by the client, not assumed. Same-origin uploads must carry the API authentication when the service requires it. - The official API returns a pre-signed object-storage URL that carries its own authorization. Do not attach the MinerU API key to a different-origin URL — that would leak the credential. Headers returned by the service (
upload_headers) are always kept as-is.
The example script implements the same rule as the Python SDK (api_client._same_origin_upload_headers): resolve relative URLs against the API base, compare scheme + host + effective port, attach the MinerU key only for same-origin uploads. Relative URLs resolve to same-origin; the same host on a different port counts as a different origin.
Downloads go through GET /v1/files/{file_id}/content, which may answer with a 302 redirect. The example follows redirects without --location-trusted, so credentials are never re-sent to a different origin (including the same host on a different port; requires curl >= 7.83.0).
Request-cycle details the script deliberately covers
- Upload lifecycle. Pass
sha256sumwhen creating the upload for integrity checking and instant reuse of an already-known file; in that case the response iscompletedand embeds thefileobject directly, so byte upload and completion are skipped. - A 200 response is not automatically valid. The script validates JSON structure at every step: IDs must be non-empty strings and statuses must belong to the supported sets; anything else fails immediately instead of entering the polling loop with a
nullID. - Bounded polling.
MAX_POLLSlimits the number of polling requests (each also spends up to the request timeout and the poll interval); when the budget is exhausted the script exits124and prints thejob_id— the job was not canceled and polling can simply resume. - Terminal states.
completed,partial,failed, andcanceledare all terminal.partialmeans some files succeeded: the script saves the artifacts of the completed files, prints per-file results including errors, and only then exits2.failedexits3,canceledexits4. - Atomic downloads. Artifacts are written to
*.partfirst and moved into place on success; acompletedjob with a failing or missing artifact download does not exit0. - Outputs. Every artifact is a
purpose:"parse_output"file; content always comes fromGET /v1/files/{file_id}/contentusing the ids underfiles[].output_files. TreatGET /v1/health(features.sources,features.output_formats) as the source of truth for what the current deployment supports; renderer formats do not imply API support.
Production notes
- Bind
--hostconsciously. The default127.0.0.1keeps the service on loopback;0.0.0.0exposes it to the network, so combine that with--api-keyor an authenticating reverse proxy. - Storage and restart boundary: file bytes live under
--upload-dir(a temporary directory that is removed on clean shutdown when not configured), but the upload/file/job resource index is in-process state. Restarting the service does not preserve oldupload_id/file_id/job ids, even when the directory is kept. This API is not a recoverable persistent job service; use the document library for persistent reading, indexing, and caching — it is not a drop-in persistent replacement for this upload/job interface. --concurrencycaps concurrent parse jobs; queue growth beyond it shows up as longerqueuedtimes, not failures.GET /v1/usagereports consumption. Use/v1/healthand the OpenAPI docs at/docs(when enabled) to separate service-side failures from client errors; check server logs before retrying afailedjob.
The V1 service does not provide legacy /file_parse or /tasks routes; see migration for older clients.