Skip to content

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.

1 — What can I print to?
curl -H "Authorization: Bearer $TOKEN" \
     https://printr.example.com/api/v1/printers
2 — Print something
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" }
     }'
3 — Did it work?
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.

Every request
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

GET /printers Everything you can print to, with live status.
GET /printers/{id} One printer.
GET /printers/languages Which languages this installation can print.

Print jobs

POST /printjobs Print something.
GET /printjobs Job history, filtered and paginated.
GET /printjobs/{id} One job, with its full event trail.
POST /printjobs/{id}/cancel Cancel a job that has not printed yet.

Computers

GET /computers The Macs running the agent, and whether they are checking in.
GET /computers/{id} One computer, with its printers embedded.

Templates

GET /templates Available label templates.
GET /templates/{slug} One template, with every published version.
POST /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.
202 Accepted
{
  "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
Retry with a new idempotency key. Reusing the original returns the original failed job rather than submitting anything — which looks a lot like a retry that silently did nothing. A key identifies one attempt, not one label.

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.
Values are stripped of characters a printer would read as commands^ 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 error and message. Validation failures instead carry message and an errors object keyed by field — handle both.
  • Timestamps are ISO 8601 with an offset.
  • Only GET /printjobs paginates, and it alone returns meta. The other lists return a complete array.
  • 600 requests a minute per token. A 429 carries Retry-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