Getting Started
DOCX to PDF HTTP API
Deploy an authenticated FastAPI service for private DOCX-to-PDF conversion with LibreOffice or Gotenberg, health endpoints, limits, and an OpenAPI 3.1 contract.
API overview
The private HTTP adapter exposes a deliberately small DOCX-to-PDF surface. Use the endpoints below for conversion, diagnostics, and deployment health checks.
| Endpoint | Authentication | Purpose |
|---|---|---|
| POST /conversions | Bearer token | Convert uploaded DOCX bytes to a PDF |
| GET /engines | Bearer token | List configured renderer capabilities |
| GET /live | None | Confirm the process is alive |
| GET /ready | None | Check that the default renderer is ready |
| GET /version | None | Return the package version |
Start the API
Install the optional API dependencies, set a strong API key, and run the application factory on port 8000.
uv sync --extra api
$env:GORDON_DOC_API_KEY = "replace-me"
uv run uvicorn gordon_doc_converter.api.app:create_app --factory --host 127.0.0.1 --port 8000
Convert a document
POST /conversions accepts only a DOCX request body and returns application/pdf. Send the original basename in X-Filename, the DOCX OOXML MIME type in Content-Type, and a Bearer token when an API key is configured. The optional engine query parameter accepts libreoffice or gotenberg; Word COM is deliberately unavailable through the API. The server stages the upload in a temporary directory, validates the OOXML package and limits, calls the configured malware-scan hook, and deletes temporary files before the response returns.
curl --fail-with-body \
-H "Authorization: Bearer replace-me" \
-H "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document" \
-H "X-Filename: report.docx" \
--data-binary @report.docx \
"http://127.0.0.1:8000/conversions?engine=libreoffice" \
--output report.pdf
Interactive API documentation
The documentation site publishes the generated OpenAPI 3.1 contract and a bundled, read-only Swagger UI. You can inspect the JSON in your browser or download it for code generation and validation tools.
View OpenAPI JSON Download OpenAPI JSON Open Swagger UIAvailable endpoints
The specification describes document conversion, engine discovery, health, readiness, and version endpoints. Protected requests use a Bearer token.
# Protected: requires Authorization: Bearer <api-key>
POST /conversions?engine=libreoffice|gotenberg
GET /engines
# Unprotected operational metadata
GET /live # {"status": "ok"}
GET /ready # 200 ready, 503 not-ready
GET /version # {"version": "0.6.0"}
Status codes and operational limits
A successful conversion returns 200 with a PDF attachment. Invalid engine choices or input return 400; missing or invalid credentials return 401; an oversized source returns 413; renderer failures return 422; exhausted rate or concurrency capacity returns 429; internal staging or service faults return 500; and unavailable authentication or malware scanning returns 503. /ready checks the configured default engine rather than merely reporting that the process is alive. The built-in fixed-window rate limit and concurrency limit are process-local, so production deployments with multiple replicas must enforce distributed limits at the ingress or gateway too.
Configuration and integration hooks
create_app accepts ApiSettings or environment defaults. GORDON_DOC_API_KEY enables the default constant-time Bearer-token comparison. GORDON_DOC_GOTENBERG_URL configures a Gotenberg adapter and makes Gotenberg the default engine; otherwise LibreOffice is used. ApiSettings also controls conversion timeout, maximum concurrent conversions, fixed-window request rate, and input limits. Supply auth_hook, malware_scan_hook, and telemetry_hook when integrating private identity, scanning, or observability systems. Telemetry receives content-free fields only; never emit document contents, credentials, or customer paths.
from gordon_doc_converter.api.app import ApiSettings, create_app
app = create_app(settings=ApiSettings(
api_key='read-from-a-secret-store',
timeout_seconds=120,
max_concurrent_conversions=2,
rate_limit_requests=30,
rate_limit_window_seconds=60,
))