Synced from docling-serve v1.21.0
This page summarizes the docling-serve documentation at v1.21.0. For the exhaustive reference, follow the links to the source repository.
REST API
The docling-serve HTTP API. Examples target a local server at http://localhost:5001; on Docling for IBM watsonx use your service base URL and key.
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/v1/convert/source |
POST | convert from URLs / base64 sources (sync) |
/v1/convert/file |
POST | convert uploaded files, multipart (sync) |
/v1/convert/source/async, /v1/convert/file/async |
POST | submit an async task |
/v1/status/poll/{task_id} |
GET | poll task status |
/v1/status/ws/{task_id} |
WebSocket | subscribe to status |
/v1/result/{task_id} |
GET | fetch a finished result |
The full, interactive schema is always available at /docs (OpenAPI / Swagger) on any running server.
Authentication
If DOCLING_SERVE_API_KEY is set on the server, send it on every request:
-H "X-Api-Key: <YOUR_KEY>"
Python client
Docling ships a Python client for the API server, so you don't have to hand-roll HTTP calls. It takes the service URL and an optional API key, and returns the same ConversionResult as the local DocumentConverter:
from docling.service_client import DoclingServiceClient
from docling.datamodel.service.options import ConvertDocumentsOptions
with DoclingServiceClient(url="http://localhost:5001") as client:
result = client.convert(
source="https://arxiv.org/pdf/2501.17887",
options=ConvertDocumentsOptions(to_formats=["md"]),
)
print(result.document.export_to_markdown())
source accepts an HTTP/HTTPS URL string, a local pathlib.Path, or a DocumentStream; for multiple inputs use convert_all(source=[...]) to stream multiple conversion results. The options are the same conversion options shown below. See the examples for more recipes.
Artifact storage on a private network
By default, the client downloads the result artifacts (presigned URLs) only from public addresses. It refuses an artifact URL on a private, loopback or link-local address, so a misconfigured or compromised service cannot point the client at your internal network. If your artifact storage is on a private network, for example MinIO in the same Kubernetes cluster or on localhost, list its origin in artifact_url_allowlist:
client = DoclingServiceClient(
url="http://docling-serve.svc.cluster.local:5001",
artifact_url_allowlist=["http://minio.storage.svc.cluster.local:9000"],
)
Each entry is an origin: scheme, host and optional port (the default port of the scheme applies when you omit it). The client checks every redirect hop, so a redirect from an allowlisted origin to another private host is still refused.
Conversion options (common)
Pass these in the JSON body under options. This is the common subset — the authoritative, full schema is the live OpenAPI docs at /docs on any running server.
| Option | Meaning |
|---|---|
from_formats / to_formats |
input / output formats (see Supported formats) |
image_export_mode |
how images are emitted (placeholder / embedded / referenced) |
do_ocr / force_ocr |
enable / force OCR |
ocr_preset / ocr_lang |
OCR preset and languages (ocr_engine is deprecated — prefer ocr_preset) |
table_mode |
table-structure mode (fast / accurate) |
pdf_backend |
PDF parsing backend |
pipeline |
processing pipeline (e.g. standard / VLM) |
| enrichment flags | code, formula, picture classification/description, chart |
For full-page VLM conversion models see Vision models; for picture-description models see Enrichment features and Model catalog.
Example: convert a URL (async)
curl -X POST "http://localhost:5001/v1/convert/source/async" \
-H "Content-Type: application/json" \
-d '{"http_sources": [{"url": "https://arxiv.org/pdf/2501.17887"}]}'
For a synchronous call use /v1/convert/source with the same body.
Example: upload a file (multipart)
The /v1/convert/file endpoint accepts one or more files as multipart/form-data, with options as form fields:
curl -X POST "http://localhost:5001/v1/convert/file" \
-H "Content-Type: multipart/form-data" \
-F "files=@2206.01062v1.pdf;type=application/pdf" \
-F "from_formats=pdf" \
-F "to_formats=md" \
-F "do_ocr=true" \
-F "image_export_mode=embedded" \
-F "table_mode=fast"
Base64 file upload
To send a file inline instead of multipart, POST to /v1/convert/source with file_sources. For large files, write the request body to a temp file and pass it with -d @file to avoid the shell's "Argument list too long" error:
# 1. base64-encode the file
B64_DATA=$(base64 -w 0 /path/to/document.pdf)
# 2. build the request body
cat > /tmp/request_body.json <<EOF
{
"file_sources": [{ "base64_string": "${B64_DATA}", "filename": "document.pdf" }]
}
EOF
# 3. POST the request
curl -X POST "http://localhost:5001/v1/convert/source" \
-H "Content-Type: application/json" \
-d @/tmp/request_body.json
Response format
A single-file conversion returns JSON:
{
"document": {
"md_content": "",
"json_content": {},
"html_content": "",
"text_content": "",
"doctags_content": ""
},
"status": "success", // success | partial_success | skipped | failure
"processing_time": 0.0,
"timings": {},
"errors": []
}
Only the *_content fields you requested via to_formats are populated. processing_time is in seconds; timings carries per-component detail when enabled. If you request the zip target, or the job produces multiple files, the response is a zip archive instead of JSON.
Asynchronous API
Both convert endpoints have /async variants. Submitting returns a task descriptor:
{
"task_id": "<task_id>",
"task_status": "pending", // pending | started | success | failure
"task_position": 1,
"task_meta": null
}
Poll until done — GET /v1/status/poll/{task_id}:
import time
import httpx
base_url = "http://localhost:5001/v1"
task = response.json() # from the /async submission
while task["task_status"] not in ("success", "failure"):
task = httpx.get(f"{base_url}/status/poll/{task['task_id']}").json()
time.sleep(5)
Subscribe via WebSocket — /v1/status/ws/{task_id} — for push updates (messages are JSON with message = connection | update | error plus the task object).
Fetch the result when finished — GET /v1/result/{task_id}.
Picture description
When picture-description (image captioning) enrichment is on, select the model with picture_description_preset (a named preset) or, for full control, picture_description_custom_config. The model can run locally (in-process) or via a remote OpenAI-compatible API endpoint; the remote path requires launching the server with DOCLING_SERVE_ENABLE_REMOTE_SERVICES=true.
Note
The older picture_description_local / picture_description_api parameters are deprecated at docling-serve v1.21.0 — migrate to picture_description_preset / picture_description_custom_config.
See Enrichment features for picture-description options, and Model catalog for available models.