Document conversion APIPublic Beta
Document conversion as infrastructure.
Not a converter you call and hope. A job pipeline with an audit trail, retries that never duplicate work, private short-lived storage and a contract that stays stable as capabilities are added.
Available now in Public Beta. Open to any workspace.
# Submit a conversion job
curl -X POST https://api.apidocinfra.com/v1/documents/convert \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: request_123" \
-F "[email protected]" \
-F "output_format=pdf"# The same request from Node or the browser
const form = new FormData();
form.append("file", new Blob([bytes]), "contract.docx");
form.append("output_format", "pdf");
const response = await fetch("https://api.apidocinfra.com/v1/documents/convert", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.DOCINFRA_API_KEY}`, "Idempotency-Key": "request_123" },
body: form,
});
const job = await response.json(); // { job_id, document_id, status: "queued" }# The same request with java.net.http
var boundary = "docinfra-" + UUID.randomUUID();
var body = MultipartBody.of(boundary, Map.of("output_format", "pdf"), Path.of("contract.docx"));
var request = HttpRequest.newBuilder(URI.create("https://api.apidocinfra.com/v1/documents/convert"))
.header("Authorization", "Bearer " + System.getenv("DOCINFRA_API_KEY"))
.header("Idempotency-Key", "request_123")
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(body)
.build();
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
// 202 {"job_id": "...", "document_id": "...", "status": "queued"}# The same request with urllib (standard library only)
import os
import urllib.request
import uuid
boundary = f"docinfra-{uuid.uuid4()}"
with open("contract.docx", "rb") as f:
file_bytes = f.read()
body = (
f"--{boundary}\r\n"
'Content-Disposition: form-data; name="output_format"\r\n\r\n'
"pdf\r\n"
f"--{boundary}\r\n"
'Content-Disposition: form-data; name="file"; filename="contract.docx"\r\n'
"Content-Type: application/octet-stream\r\n\r\n"
).encode() + file_bytes + f"\r\n--{boundary}--\r\n".encode()
request = urllib.request.Request(
"https://api.apidocinfra.com/v1/documents/convert",
data=body,
headers={
"Authorization": "Bearer " + os.environ["DOCINFRA_API_KEY"],
"Idempotency-Key": "request_123",
"Content-Type": f"multipart/form-data; boundary={boundary}",
},
)
with urllib.request.urlopen(request) as response:
job = response.read() # {"job_id": "...", "document_id": "...", "status": "queued"}# 202 Accepted
{
"job_id": "job_01J9Z3F8Q6W2XK4B7C9D0E1F2G",
"document_id": "doc_01J9Z3F8Q5M8N3P4R5S6T7V8W9",
"status": "queued",
"created_at": "2026-09-23T15:58:46Z"
}# Poll the job, then download the result
GET /v1/jobs/job_01J9Z3F8Q6W2XK4B7C9D0E1F2G
Authorization: Bearer $API_KEY
{
"job_id": "job_01J9Z3F8Q6W2XK4B7C9D0E1F2G",
"status": "completed",
"document_id": "doc_01J9Z3F8Q5M8N3P4R5S6T7V8W9",
"created_at": "2026-09-23T15:58:46Z",
"completed_at": "2026-09-23T15:58:50Z",
"download_url": "https://…/processed/…?X-Amz-Expires=300&X-Amz-Signature=…",
"download_url_expires_at": "2026-09-23T16:03:52Z"
}Real endpoints and fields from the API contract. Replace the key and the file.
What makes it infrastructure
Jobs, not requests
Every conversion is a job you can poll, subscribe to and find later by id. Nothing heavy ever runs inside the HTTP request.
Idempotent writes
Repeating a request with the same Idempotency-Key returns the same job. Retries are free and safe.
Isolation by default
Engines run in containers with no network egress; uploads are scanned before they are opened.
Append-only audit
Received, scanned, converted, downloaded, deleted: each step with account, time and outcome.
Metered per workspace
GET /v1/usage tells you what counted this month, and only successful work counts.
One API for what comes next
AI Rewrite already runs on the same jobs; PDF tools, signatures and extraction will too.
A conversion, step by step
- 1
Your app uploads the file with an API key and an Idempotency-Key; the API validates the type by content and stores the original.
- 2
A worker claims the job, scans it, converts it and stores the result; each step leaves an audit entry.
- 3
Your app polls the job or receives a signed webhook, downloads the result through a short-lived link, and the files are deleted after 24 hours.
Questions
- What can I convert today?
- DOCX and HTML to PDF, in public beta. The roadmap lists XLSX, PPTX, images, PDF/A and PDF tools.
- How do you handle failures?
- Transient errors are retried in place with backoff; permanent ones end the job with a stable error code and a fixed message, never the engine output.
- Can I run it in my own cloud?
- Private deployments are designed for and on the roadmap. Today the service runs as a managed public beta.