Print jobs and documents
A job is one thing to print, sent to one printer, with the options that go with it. Content arrives inline as a URL or as base64, or as a document you uploaded once and can print many times.
Two behaviours here catch people out, so they have sections of their own rather than a footnote. Capability mismatches never reject a job: ask for duplex on a printer that does not report duplex support and the job is accepted with a warning attached, because capability reporting is best effort and refusing to print would be worse than printing wrong. And some drivers cannot confirm that a page physically came out, so a successful job carries completion_confidence telling you whether the printer said so or only the spooler did.
Documents
Jobs can carry their content inline, but a document can be uploaded once and printed many times: one packing-slip PDF sent to three printers, for example, instead of re-sending or re-hosting the same bytes.
| Method | Path | Notes |
|---|---|---|
| POST | /documents | Either a direct upload (content_type: application/pdf, body up to 50 MB) or { "source_url": "...", "fetch_auth": {...} } for a server-side fetch |
| GET | /documents/{id} | |
| DELETE | /documents/{id} |
Documents expire after 24 h by default; override with expire_after_seconds.
Jobs
| Method | Path | Notes |
|---|---|---|
| POST | /jobs | Create (see below). Returns 201 with the full job object. |
| GET | /jobs | Filters: printer_id, device_id, status, created_after/created_before, metadata[...] |
| GET | /jobs/{id} | |
| POST | /jobs/{id}/cancel | Cancels if the job is not yet in a terminal state. Returns 409 job_not_cancelable if it is already printing or finished. |
| GET | /jobs/{id}/events | Ordered state-transition timeline for the job |
Create request (send Idempotency-Key as a header, not a body field):
{
"printer_id": "prn_8f2k1",
"title": "Order #12345 label",
"content": {
"format": "pdf", // pdf | raw (ZPL/ESC-POS/etc.)
"url": "https://...", // exactly one of url | base64 | document_id
"base64": "...",
"document_id": "doc_2ka9x",
"fetch_auth": { "type": "basic", "username": "...", "password": "..." } // only with url
},
"copies": 2,
"options": {
"duplex": "long_edge", // long_edge | short_edge | none
"color": false,
"paper": "A4",
"dpi": "300x300",
"page_ranges": "1,3-5",
"tray": "Tray 2",
"media": null,
"collate": true,
"fit_to_page": true,
"rotate": 0,
"pages_per_sheet": 1
},
"queue_if_offline": true, // false → rejected immediately with 422 printer_offline
"expire_after_seconds": 3600, // default 86400 (24 h)
"metadata": { "order_id": "12345" }
}
Job object:
{
"id": "job_5tq8p",
"object": "job",
"printer_id": "prn_8f2k1",
"device_id": "dev_7hk2m",
"title": "Order #12345 label",
"status": "printing",
"copies": 2,
"options": { ... },
"completion_confidence": null, // set on success: "printer" | "spooler" (see below)
"warnings": [ // non-fatal notices; the job still proceeds
{ "code": "option_unsupported", "message": "duplex printing requested but the printer does not report duplex support." }
],
"error": null, // { "code": "printer_error", "message": "Out of paper" } when failed
"created_at": "...",
"queued_at": "...",
"sent_at": "...",
"completed_at": null,
"expires_at": "...",
"metadata": { "order_id": "12345" }
}
Status lifecycle (a single status field, with strict transitions):
created ──► queued ──► sent ──► printing ──► succeeded
│ │ │
├──────────┴──────────┴──────► failed (terminal, error populated; straight from
│ queued when the agent can't start the job)
├────────────────────────────► canceled (terminal, via /cancel)
└────────────────────────────► expired (terminal, expire_after elapsed)
queued: accepted, waiting for the device to come online and pick it upsent: delivered to the agent and handed to the OS spoolerprinting/succeeded: reported wherever the OS driver supports it
Some drivers cannot confirm that a page actually came out. Those jobs go sent → succeeded when the spooler finishes, and the job carries "completion_confidence": "spooler" instead of "printer". If a print must be confirmed at the hardware, check that field rather than status alone.
Copies
copies is a single top-level field. PrintSocket hands it to the platform's own copy mechanism (-n on CUPS, DEVMODE on Windows, repeating the payload for raw content) rather than queuing the job several times. One job in, one job in the print queue.
Warnings
Capability mismatches are never rejected. Requesting an option the printer doesn't report support for doesn't fail the job. Capability reporting is best-effort and agents can't always know. The job is accepted with a warnings entry attached, and webhook payloads carry the warnings too, so you can surface them without blocking prints that would have worked. raw content is likewise passed through to the printer unvalidated.
| Warning code | Meaning |
|---|---|
option_unsupported | An option was requested that the printer's reported capabilities don't cover (e.g. color: true or a duplex mode on a printer reporting neither). The option is passed to the driver anyway. |
copies_exceeds_max | copies is greater than the printer's reported copies_max. Behavior beyond the maximum is driver-defined. |