API reference
A REST API for applications that need to print labels. Bearer tokens, JSON in and out, and idempotency keys so a retry never costs you a second label.
Quick start
Three requests: find a printer, print to it, check it worked.
curl -H "Authorization: Bearer $TOKEN" \
https://printr.example.com/api/v1/printers
curl -X POST https://printr.example.com/api/v1/printjobs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1041-label" \
-d '{
"printer_id": 7,
"template": "shipping-label",
"data": { "order": "SO-1041", "customer": "Acme Ltd" }
}'
curl -H "Authorization: Bearer $TOKEN" \
https://printr.example.com/api/v1/printjobs/8814
Authentication
Every request carries a bearer token. Create one in the dashboard under Settings → API tokens; it is shown once at creation and cannot be recovered afterwards, so store it where your application reads its secrets.
Authorization: Bearer 1|abc123…
A token is scoped to the account that created it. A resource
belonging to another account answers
404, never
403 — telling you it exists would leak
that someone else has it.
Endpoints
Base URL https://your-printr-host/api/v1.
Printers
/printers
Everything you can print to, with live status.
/printers/{id}
One printer.
/printers/languages
Which languages this installation can print.
Print jobs
/printjobs
Print something.
/printjobs
Job history, filtered and paginated.
/printjobs/{id}
One job, with its full event trail.
/printjobs/{id}/cancel
Cancel a job that has not printed yet.
Computers
/computers
The Macs running the agent, and whether they are checking in.
/computers/{id}
One computer, with its printers embedded.
Templates
/templates
Available label templates.
/templates/{slug}
One template, with every published version.
/templates/{slug}/render
Render without printing — preview in your own UI.
Printing a label
Address a printer by printer_id, or by
device_id plus
printer_key — the second survives a
computer being re-enrolled, which renumbers its printers.
Then send either a template with
data, or raw
markup of your own.
| Field | Type | Notes |
|---|---|---|
| printer_id | integer | Required unless you address by device and key. |
| template | string | Template slug. Either this or raw. |
| data | object | Values for the template's variables. |
| raw | string | Label markup, up to 2 MB. Either this or template. |
| language | string | Language of a raw payload. Defaults to the printer's own. |
| copies | integer | Defaults to 1. |
| ttl_seconds | integer | Expire if unprinted after this long. Defaults to 900; 0 means never. |
| title | string | Your own reference, shown in the dashboard. |
{
"data": {
"id": 8814,
"state": "queued",
"printer_id": 7
}
}
Job states
A job is in exactly one state. The four terminal ones never change again, so you can stop polling the moment you see one.
| State | Meaning | Terminal |
|---|---|---|
| queued | Accepted and waiting for the computer to collect it. | — |
| dispatched | The agent has it. | — |
| printing | Being written to the printer. | — |
| printed | The bytes reached the printer. | Yes |
| failed | Something stopped it. Carries an error code. | Yes |
| cancelled | Cancelled before it printed. | Yes |
| expired | Not printed before its TTL elapsed. | Yes |
Errors
A failed job carries one of these, each with a
retryable flag so you do not have to
guess which failures are worth sending again.
| Code | Meaning | Retryable |
|---|---|---|
| printer_unreachable | Nothing answered at the printer. | Yes |
| printer_error | The printer reported a fault. | Yes |
| write_timeout | The connection stalled mid-write. | Yes |
| internal | Our fault. | Yes |
| unsupported_language | The agent cannot print that language. | No |
| payload_invalid | The label markup was malformed. | No |
| job_expired | Its TTL elapsed first. | No |
| cancelled | Someone cancelled it. | No |
Templates
Keep label layout on the server and send data instead of markup. Versions are immutable, so a job records exactly what it rendered and a bad edit is one rollback rather than an incident.
| Syntax | Meaning |
|---|---|
| {{ order }} | Insert a value, sanitised. |
| {{ order.customer.name }} | Dotted paths read into nested data. |
| {{ block|raw }} | Insert verbatim. Only for markup you generate yourself. |
^ and
~ for ZPL,
" and \ for
TSPL2. That is what stops a customer's name from rewriting the label.
Idempotency
Send Idempotency-Key on a
POST /printjobs and a repeated request
returns the original job with 200
instead of printing again — including when two retries race each
other. Keys are scoped to your account.
Reusing a key with a different body still returns the first job. The key wins, not the payload.
Conventions
- Successful responses wrap their payload in
data. Errors do not. - Printr's own errors carry
errorandmessage. Validation failures instead carrymessageand anerrorsobject keyed by field — handle both. - Timestamps are ISO 8601 with an offset.
- Only
GET /printjobspaginates, and it alone returnsmeta. The other lists return a complete array. - 600 requests a minute per token. A
429carriesRetry-After. - Job outcomes are polled rather than pushed. Poll until you see a terminal state.
Try it against your own printers
A trial account comes with the same reference filled in with your printer ids, so the examples run as written.
Start free trial