Chapter 4. HTTP API Reference
Chapter 4. HTTP API Reference
4.1 General rules
| Item | Convention |
|---|---|
| Base URL | http://127.0.0.1:8899 (local by default; change bind for LAN); with TLS, https://…:8898 serves the same routes |
| Content type | UTF-8 JSON for requests and responses (except file uploads) |
| Timestamps | Unix milliseconds |
| Authentication | Any of: Authorization: Bearer <t> / X-Wxprint-Token: <t> / ?token=<t>; anonymous when no token is set |
| Coordinate unit | Millimeters (mm, floating point) |
Interface split: the HTTP API targets backend languages (stateless
request/response — submit, get a job_id, query status when needed);
WebSocket targets web pages (event push, Chapter 5). Inputs are
isomorphic and the render pipeline is identical; the split is a
recommendation, not a restriction.
4.2 Error envelope and codes
All non-2xx responses share one envelope:
{ "error": { "code": "E_DATA_FETCH", "message": "failed to fetch data",
"detail": { "url": "https://…", "status": 502 } } }
| HTTP | code | Scenario |
|---|---|---|
| 400 | E_BAD_REQUEST |
Missing or ill-typed parameter |
| 401 | E_AUTH |
Token missing or wrong (only when a token is set) |
| 403 | E_URL_BLOCKED |
URL hit the security policy |
| 404 | E_TEMPLATE_NOT_FOUND / E_PRINTER_NOT_FOUND / E_JOB_NOT_FOUND |
Resource not found |
| 409 | E_PRINTER_OFFLINE / E_JOB_STATE |
Printer unavailable / job state forbids the operation |
| 413 | E_LIMIT |
Template/data over the size limit (10MB default) |
| 422 | E_TEMPLATE_INVALID / E_DATA_INVALID / E_DATA_FETCH |
Template validation failed / JSON parse failed / data URL fetch failed |
| 500 | E_RENDER / E_PRINT |
Render failure / print failure |
| 504 | E_TIMEOUT |
Fetch/render/print timeout |
E_TEMPLATE_INVALID detail locates the exact field (e.g.
elements[3].text); E_DATA_FETCH detail carries the URL and the
upstream status code.
4.3 GET /api/version — version and capability negotiation
{ "name": "wxprint-server", "version": "1.0.3",
"kinds": ["overlay", "html"], "engines": ["twig-compat/1"] }
| Field | Type | Description |
|---|---|---|
version |
string | Server version |
kinds |
string[] | Supported template kinds (overlay / html) |
engines |
string[] | Template engine and compatibility-layer versions |
4.4 GET /api/printers — printer list
{ "printers": [
{ "name": "HP-LaserJet-M1005", "default": true, "state": "ready",
"calibrated": true }
] }
| Field | Type | Description |
|---|---|---|
name |
string | Printer name (use as the printer parameter) |
default |
bool | Whether it is the system default |
state |
string | ready / offline (other platform states fold into these) |
calibrated |
bool | Whether overlay calibration data exists (Section 7.10) |
4.5 POST /api/print — submitting a print
Request fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
template |
string | object | ✓ | — | Template reference; three forms below |
data |
any | object | ✓ | — | Print data; three forms below |
printer |
string | default | Printer name (the name from GET /api/printers) |
|
copies |
int | 1 | Whole-batch repetitions | |
copies_per_record |
int | 1 | Per-record copies (triplicate form = 3) | |
collate |
bool | true | Page order: true = record×copy×batch (all copies of one record first); false = copy-major | |
pages |
string | all | Page selection, e.g. "1-3,5" |
|
task_name |
string | template name | Task name (shown in the system print queue) | |
preview |
bool | false | true = render only, no paper (preview job, Section 4.8) |
Three template forms:
| Form | Notation | Notes |
|---|---|---|
| By id | "invoice-a4" |
References a registered template (~/.wxprint/templates/<id>/; inline submissions are not registered — upload via POST /api/templates to reuse by id) |
| URL | {"url": "https://…/tpl.json"} |
The server fetches the template JSON (subject to fetch size/timeout limits) |
| Inline | { "id": …, "kind": "overlay", … } |
Full template object (format in Chapter 7; assets must be URL/data:) |
Three data forms (matching the loadData/loadJSON/loadURL verbs):
| Form | Notation | Notes |
|---|---|---|
| Inline | {…} or […] |
Array = batch: each record renders one page (multi-page templates render per record); {"records": […]} is equivalent |
| JSON text/file | {"json": "…"} or {"path": "…"} |
JSON string; path is a server-side file (restricted to ~/.wxprint/data/ by default) |
| URL | {"url": …, "headers": {…}, "timeout_s": 10} |
Fetched at run time (“URL + JSON at print time”); headers passes auth headers through |
Response
{ "job_id": "j_01J8…", "total_pages": 6, "status": "queued" }
| Field | Type | Description |
|---|---|---|
job_id |
string | Job identifier (for later query/cancel/print) |
total_pages |
int | Total pages (batch = records × pages-per-record × copies × batches) |
status |
string | Always queued |
Examples
Single document + inline data:
curl -s -X POST http://127.0.0.1:8899/api/print \
-H "Content-Type: application/json" -d '{
"template": "invoice-a4",
"data": { "no": "INV-2026-1042", "amount": 1280.50,
"customer": { "name": "Example Tech Ltd" } },
"printer": "HP-LaserJet-M1005" }'
Batch of 2 records, 3 copies each:
curl -s -X POST http://127.0.0.1:8899/api/print \
-H "Content-Type: application/json" -d '{
"template": "sf-waybill-100x93",
"data": [ {"waybill_no":"SF123", "receiver": {"name":"Alice"}},
{"waybill_no":"SF124", "receiver": {"name":"Bob"}} ],
"printer": "HP-LaserJet-M1005",
"copies_per_record": 3 }'
URL template + URL data (fetched at print time with auth headers):
curl -s -X POST http://127.0.0.1:8899/api/print \
-H "Content-Type: application/json" -d '{
"template": { "url": "https://erp.example.com/tpl/invoice.json" },
"data": { "url": "https://erp.example.com/api/invoice/2026-1042",
"headers": { "Authorization": "Bearer erp-token" },
"timeout_s": 10 } }'
4.6 POST /api/preview — preview (no paper)
Request body as /api/print (printer/copies*/pages ignored). Query
parameters:
| Parameter | Default | Description |
|---|---|---|
format |
pdf |
pdf = full multi-page PDF (application/pdf); png = single-page PNG |
page |
0 | Page number for PNG mode (0-based) |
dpi |
150 | Rasterization DPI for PNG mode |
PNG goes through the same render pipeline as printing (pdf_oxide rasterization) — the pixels are exactly what prints.
4.7 GET /api/jobs/{id} — job status
{ "job_id": "j_01J8…", "status": "printing", "page_done": 4, "total_pages": 6,
"printer": "HP-LaserJet-M1005", "template": "sf-waybill-100x93",
"created_at": 1760764000000, "finished_at": null, "error": null,
"warnings": ["elements[3].text: variable remark not found"] }
| Field | Type | Description |
|---|---|---|
status |
string | queued / rendering / printing / done / failed / cancelled |
page_done |
int | Pages completed (batch progress) |
total_pages |
int | Total pages |
error |
object | null | {code, message} on failure |
warnings |
string[] | Non-fatal warnings (unresolved variables, table truncation, …) |
created_at / finished_at |
int | Unix milliseconds |
State machine: queued → rendering → printing → done; failure or
cancellation moves from any render/print state to failed/cancelled.
4.8 Job control endpoints
| Endpoint | Method | Body | Description |
|---|---|---|---|
/api/jobs/{id}/cancel |
POST | — | Cancel: immediate while rendering; stops remaining pages while printing |
/api/jobs/{id}/print |
POST | {"printer": "…"} |
Commit a preview job to paper (empty printer = system default); response {"job_id", "printer", "status": "printing"} |
/api/jobs/{id}/pdf |
GET | — | Download the PDF kept for a done job (Content-Disposition: attachment; preview jobs / not-yet-released render output) |
/api/jobs/{id}/page/{page} |
GET | — | Single-page PNG of a done job (page number 0-based; ?dpi=150 adjustable) |
“Submit without printer + preview: true → confirm in preview →
commit via this endpoint” is the preview-then-print flow (native tray
window / web component).
4.9 Template management endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/templates |
GET | List: [{id, name, kind, version, mtime}] |
/api/templates/{id} |
GET | The template JSON |
/api/templates |
POST | Register a template (below) |
/api/templates/{id} |
DELETE | Delete (running jobs unaffected) |
POST /api/templates takes a full template JSON object as the
request body (format in Chapter 7; written to
~/.wxprint/templates/<id>/template.json). Response
{"id": "…", "warnings": […]}; an invalid id or directory-creation
failure returns 422 E_TEMPLATE_INVALID (rules in Section 7.11).
4.10 Printer calibration endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/printers/{name}/calibration |
GET | Read the printer’s calibration data (no data → E_PRINTER_NOT_FOUND) |
/api/printers/{name}/calibration |
PUT/POST | Write calibration: {"offset_mm": {"x": 0.35, "y": -0.2}, "scale": {"x": 1.0002, "y": 1.0002}} |
/api/printers/{name}/calibration-page |
POST | Generate the calibration-page PDF (crosshair rules + mm grid); print it and measure the deviation |
Calibration flow: print via calibration-page → measure → write with
PUT calibration → every overlay job on that printer applies it before
rendering (Section 7.10).
4.11 POST /api/saveas — export
Request body as /api/print; the export format goes in the ?format=
query parameter:
| format | Product | Notes |
|---|---|---|
pdf |
PDF file stream | All pages |
png |
PNG file stream | First page |
zip |
ZIP file stream | One PNG per page (?dpi=150 adjustable) |
The response is a file stream (Content-Disposition: attachment).
4.12 Status page and preview component page
GET /: a read-only status page (version, listen addresses incl. TLS, printers, recent jobs) — the one-glance health check.GET /preview/{job_id}: the web preview component for headless deployments (PNG paging + zoom + printer dropdown + print + save-as). Query parameters:
| Parameter | Description |
|---|---|
hide_print / hide_save |
Hide the “Print” / “Save” buttons |
token |
Auth pass-through (for <img>/window.open that cannot set headers) |