Skip to content
Docs menu · Sending jobs
Get started / Sending jobs

Sending jobs

A job is one thing to print. Send it with an SDK print helper, such as printPdf or printText, using an API key with the jobs:write scope.

Printing with an SDK

Each SDK has a helper per kind of content — text, receipt commands, templates, PDFs and images — and jobs.create for everything else. Every helper returns the job.

// A PDF on one printer: a file path or bytes
const invoice = await cz.printPdf("invoice-2041.pdf", { printerId, title: "Invoice 2041", copies: 2 });

// Plain text to the kitchen printer at one location
await cz.printText("TABLE 7\n2 x Eggs on toast\n  + bacon\n1 x Banana bread", { role: "kitchen", locationId });

// Anything else (an Office file, scheduled for later…) with jobs.create
await cz.jobs.create({ content: menuBytes, fileName: "menu.docx", role: "office", scheduledFor: "2026-10-13T07:00:00Z" });

Job fields

Every helper takes these options. The SDKs name them the way each language does: printerId in Node.js and PHP, printer_id in Python, PrinterID in Go, .printer(…) in Rust. Unknown fields are rejected, so typos show up straight away.

FieldTypeWhat it does
kindstringOne of commands, template, text, escpos, image, pdf, document. Optional when it can be inferred: commands if you send commands, template if you send a template ID, document with a file.
rolestringPrint on a printer with this role, such as receipt or kitchen.
location_idUUIDPrefer a printer at this location.
printer_idUUIDPrint on this exact printer. Skips routing.
commandsarrayReceipt commands to print.
template_idUUIDA template to fill in with data.
dataobjectValues for the template's placeholders.
contentstringThe document. Plain text for kind: text; base64 for every other kind.
sealed_contentstringThe document sealed to the server key, base64. Use instead of content.
file_idUUIDA file uploaded with POST /v1/files (signed-in apps only).
file_namestringOriginal file name, used to recognise Office documents (for example .docx).
titlestringUp to 200 characters. Shown in the console.
referencestringYour own reference, up to 120 characters — an order or invoice number. Searchable.
copiesinteger1 to 50. Defaults to 1.
idempotency_keystringUp to 200 characters. Repeating a key returns the first job instead of printing again.
scheduled_forRFC 3339 timeHold the job until this time, up to 30 days ahead.
optionsobjectExtra print options passed to the station.
livebooleanOnly for signed-in people: false sends an unbilled test job (Developer role and up). API keys ignore it; the key's own mode decides.

You get the job back. A job made with a test key has "live": false and is never billed.

Job kinds

KindSendPrinted as
commandscommandsESC/POS on receipt printers; a simple PDF on office printers.
templatetemplate_id + dataSame as commands, after filling in placeholders.
textcontent as plain textPlain lines on receipt printers; a PDF on office printers.
escposcontent: raw ESC/POS bytes, base64Sent as-is. Receipt printers only.
imagecontent: PNG or JPEG, base64Dithered raster on receipt printers; the image on photo and office printers.
pdfcontent: PDF, base64Printers that take PDFs (computer and office printers).
documentcontent + file_name, or file_idPDFs, images and text are detected; Word, Excel, PowerPoint, OpenDocument, RTF and CSV are converted to PDF.

Content can be up to 50 MB. Office conversion needs a printer that takes PDFs. The SDKs detect PDFs and images for you and base64-encode content before sending it.

How a printer is chosen

  1. If you send printer_id, that printer is used.
  2. Otherwise your organization's routing rules are checked in priority order. A rule can match the role, the source (api, console, app) and the location, and can set the number of copies.
  3. If no rule matches, CatzPrint picks the best printer with the role (at the location, if given) — enabled, on a connected station and ready first.

If nothing matches you get 422 no_printer. If the owner has disabled the station or location, its policy decides: the job is held until it's back on, sent to a printer with the same role at a fallback location, or refused with 409 printer_disabled.

Job statuses

StatusMeaning
scheduledWaiting for scheduled_for.
heldThe printer, station or location is turned off. It prints once it's turned back on.
queuedReady, waiting for the station to be online.
sentDelivered to the station; waiting for it to confirm.
printingThe station is printing it.
printedDone.
failedThe printer or station reported a problem. status_detail says what, in plain English.
cancelledCancelled before it printed.

Jobs that a station doesn't confirm are sent again automatically, up to five times. Queued or held jobs that can't be delivered within 24 hours fail, so nothing prints a day late by surprise.

Test jobs

Test jobs print on real printers but are never billed and don't count against free prints or an allowance. They have "live": false and "billed_as": "test", and test mode allows up to 200 prints a day.

  • From code: use a test key (cz_test_…). Every job it sends is a test job.
  • From the console: people with the Developer role or higher can switch the Playground (or Print) to Test, which sends "live": false. The job's source is playground. Lower roles get 403 forbidden.

Listing and managing jobs

With jobs:read, jobs.list returns one page of jobs, newest first, and jobs.iterate (iter in Python and Rust, all in PHP, Iter in Go) walks every page. Filter by status, printer, station, location, source, live or test, a search on reference, title and ID, and a start time. jobs.get returns one job with its event history. With jobs:write you can cancel, retry and reprint.

// Every failed or held job since midnight, page by page (jobs:read)
for await (const job of cz.jobs.iterate({ status: ["failed", "held"], since: "2026-10-12T00:00:00Z" })) {
  console.log(job.id, job.status, job.status_detail);
}

// jobs:write
await cz.jobs.cancel(jobId);  // scheduled, held, queued or sent
await cz.jobs.retry(jobId);   // failed or held
await cz.jobs.reprint(jobId, { printerId: otherPrinterId });

In the console and apps, viewers are read-only: they can't print, cancel or change any job (403 “Viewers can look but not print or change jobs.”). Individuals can cancel their own scheduled, held, queued or sent jobs. Operators and above can cancel any job, and only they can retry or reprint. Cancelling someone else's job without the Operator role answers 403 with “You can only cancel your own print jobs.”

Retention

CatzPrint keeps the document of a job (its content) for 30 days after the job finishes, and files uploaded with POST /v1/files for 7 days, by default. CatzPrint administrators configure both periods.

After that the content is deleted. The job record — title, reference, status and times — stays for history and billing. Reading the preview or content, or reprinting, answers 410 content_deleted; send the document again as a new job instead.

TipKeep your own list in sync with webhooks instead of polling. Use the job list to catch up after downtime.

Without an SDK

The SDKs call these endpoints; use them directly only if no SDK fits. Create a job with POST /v1/orgs/{org}/jobs and a JSON body of the fields above, with content base64-encoded (see the HTTP (cURL) tab above). List with GET /v1/orgs/{org}/jobs (status comma-separated, printer_id, station_id, location_id, source, live, q, since, limit 1–200, cursor), fetch one with GET …/jobs/{id}, and change one with POST …/jobs/{id}/cancel, /retry or /reprint. See the API reference.