If your team builds software around printing — an ERP that fulfils orders, a WMS that drives a warehouse floor, an in-house dashboard your operators live in — you've probably hit one of two walls.
Wall one: every printer brand has its own SDK, its own driver assumptions, its own quirks. Building a fleet that's half Zebra, half TSC, plus a couple of Epson ColorWorks for color labels means three integrations and three on-call rotations. Wall two: the existing label "APIs" you've evaluated are basically file-upload endpoints. They print one PDF, return a job ID, and stop there. There's no fleet view, no template versioning, no event stream when a label fails halfway through a 1,000-label batch.
The LabelInn REST API is built for the second case. It's a single, versioned, OpenAPI-specced surface that handles printing, fleet management, design CRUD, batch operations, webhooks, audit trails, and quota — across every printer LabelInn supports. This guide walks through the surface, the auth model, idempotency, rate limits, and the integration patterns we see most often.
Base URL & Versioning
The API is hosted at:
https://api.labelinn.com/v1
The /v1 prefix is permanent. Breaking changes ship as /v2; /v1 is supported for at least 18 months after a successor's GA. Additive changes (new optional fields, new endpoints) land on /v1.
The full OpenAPI 3.0.3 spec is published — point your codegen tool at it and you have a typed client in any language in under a minute.
Authentication
LabelInn uses API keys with Bearer auth:
curl https://api.labelinn.com/v1/print/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json"
Generate keys in Settings → API Keys in your LabelInn dashboard. We recommend creating scoped keys per use case:
- Print-only key for the ERP that submits jobs — no design writes, no key rotation
- Read-only key for dashboards and analytics — no print, no writes
- Full-access key only for admin tooling, kept on a single trusted host
Test keys (sk_test_*) hit a sandbox that never touches a physical printer — perfect for CI. Live keys (sk_live_*) drive real hardware.
The Endpoints That Matter
POST /v1/print/jobs — Submit a Print Job
The workhorse. Three input modes: a saved design, raw ZPL, or a hosted image URL.
POST /v1/print/jobs
{
"printer_id": "prn_warehouse_a_01",
"design_id": "dsg_shipping_pro",
"variables": {
"order_id": "ORD-45123",
"customer_name": "Jane Doe",
"tracking_url": "https://track.example.com/45123"
},
"copies": 2
}
Response:
{
"id": "job_01HVZK...",
"status": "queued",
"printer_id": "prn_warehouse_a_01",
"queued_at": "2026-05-07T09:14:22.103Z"
}
Status transitions: queued → printing → completed (or failed). Use webhooks to be told; don't poll.
POST /v1/print/batch — Submit Up to 100 Jobs Atomically
For end-of-day order runs. The batch is accepted or rejected as a unit (any invalid job fails the batch with field-level errors), then each child job runs through the normal queue. You get an array of job IDs back.
GET /v1/print/jobs — List & Filter
Query params: status, printer_id, design_id, created_after, created_before, limit (max 100), cursor. Cursor pagination — never page-number — so the API stays correct under heavy churn.
POST /v1/print/jobs/:id/reprint and /retry
Reprint creates a new job with the same payload (your call — for re-shipping). Retry re-queues the original after a transient failure (driver, network, paper jam) and is idempotent within a 24h window. Use retry for ops automation; use reprint for human re-runs.
GET /v1/fleet/printers — Inventory and Status
Returns every printer your company owns, with model, firmware, supported media sizes, current status (online, offline, busy, error), queue depth, and last error. Use it to power a fleet dashboard or to pick a healthy target before submitting a job.
GET / POST / PUT /v1/designs — Template CRUD
Read your template library, create new designs from a JSON description, or update existing ones programmatically. Combined with POST /v1/designs/:id/publish you have full version control: every published snapshot is immutable and has a snapshot_id you can pin in your print calls.
POST /v1/render — Render Without Printing
Useful for previews, audits, or feeding a PDF into another system. Pass a design + variables, get back a PNG or PDF URL. Async by default — for AI agents and long-running renders, the response is a job ID you poll or webhook on.
POST / GET / DELETE /v1/webhooks — Event Subscriptions
Subscribe to events. The five most useful:
job.completed— a label printed successfullyjob.failed— printer rejected, paper out, ZPL error, etc., with structured error fieldsprinter.offline— driver heartbeat missedprinter.online— recovereddesign.updated— someone published a new snapshot of a design your system depends on
Events are signed (HMAC-SHA256 over the body, your endpoint secret as the key). Retry policy: 1s → 5s → 25s → 60s, up to 5 attempts. After 50 consecutive failures the subscription auto-disables and we email the owner.
Idempotency
Every POST accepts an Idempotency-Key header. We cache the response for 24 hours and return the same body on duplicates. This is the single biggest reliability lever your integration has — set it, and a network blip during a 1,000-job end-of-day batch can never produce 1,000 duplicate prints.
curl https://api.labelinn.com/v1/print/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: order-45123-shipping-v2" \
-H "Content-Type: application/json" \
-d '{...}'
Choose keys that include both the business ID and the job purpose — order-45123-shipping-v2 not just 45123 — so a customer-service reprint isn't deduped against the original.
Rate Limits
| Plan | Daily quota | Burst (per minute) | Concurrent jobs |
|---|---|---|---|
| Pro | 2,000 requests | 60 | 20 |
| Business | 10,000 requests | 120 | 60 |
| Enterprise | 50,000 requests (negotiable) | 300 | 500 |
Limits are returned on every response in X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. A 429 includes a Retry-After header in seconds — back off, don't hammer.
Need higher limits? Enterprise customers regularly run 100k+ jobs/day. Talk to us. Contact sales →
Error Model
Every error is a JSON body with a stable code, a human message, and a details object. The code is what you switch on:
{
"error": {
"code": "printer_offline",
"message": "Printer prn_warehouse_a_01 is offline.",
"details": {
"printer_id": "prn_warehouse_a_01",
"last_seen": "2026-05-07T08:42:11.000Z"
}
}
}
Common codes: invalid_argument, printer_offline, printer_busy, design_not_found, quota_exceeded, idempotency_key_conflict, media_mismatch (the design's media size doesn't fit the printer's loaded label).
Common Integration Patterns
Pattern 1: ERP Submits, App Prints
Your ERP holds orders. When a packer marks an order ready, the ERP fires POST /v1/print/jobs with the order's design and variables. The LabelInn cloud queues the job and pushes it to the right printer. Your ERP gets a job.completed webhook and updates the order status. End-to-end latency is typically 1.5–4 seconds depending on printer warm-up.
Pattern 2: Sidecar Service for Legacy Printer Code
You have a Windows service that's been printing labels via the Zebra ZPL SDK for years. Replacing it is risky. Instead, point it at the LabelInn API as a drop-in: keep your ZPL templates, send them via POST /v1/print/jobs with "raw_zpl": "...", and you immediately gain the fleet view, retry semantics, and audit trail without touching your business logic.
Pattern 3: Multi-Site Routing
Your company has three warehouses, each with their own printers. Tag your printers with site IDs in LabelInn, then submit jobs with "site_id": "warehouse_b" instead of a specific printer_id — LabelInn's edge router picks the healthiest printer at that site and falls over to the next-closest if the first is offline.
Pattern 4: Audit-Heavy Industries
Pharma, food traceability, regulated electronics. You need to prove which design version printed which serial number to which physical printer at what timestamp. LabelInn's design snapshot mechanism plus per-job audit log gives you that out of the box. Plug your serial number pool into the design as a variable, gate publication behind your QA workflow, and the API will refuse to print anything that drifts from an approved snapshot.
Webhooks: Don't Poll
Polling GET /v1/print/jobs/:id works, but it scales badly. Set up a webhook on job.completed and job.failed the same day you wire up your first POST /v1/print/jobs call. Sample receiver in Node:
app.post('/labelinn-webhook', (req, res) => {
const sig = req.header('LabelInn-Signature');
const computed = hmacSha256(req.rawBody, process.env.WEBHOOK_SECRET);
if (!timingSafeEqual(sig, computed)) return res.sendStatus(401);
const evt = JSON.parse(req.rawBody);
if (evt.type === 'job.failed') {
notifyOps(evt.data.job_id, evt.data.error);
}
res.sendStatus(200);
});
Always respond 200 within 10 seconds. Do the heavy work in a background queue — webhook timeouts trigger retries, which create duplicate processing.
What's Not in the API (Yet)
- Realtime job streaming — for now use webhooks. A WebSocket / Server-Sent-Events firehose is on the 2026 roadmap for ops dashboards.
- Multi-currency billing exposed via API — billing is dashboard-only today; programmatic invoice retrieval lands later this year.
- Cross-tenant federation — managed service providers wanting parent-key delegation: contact us for the early-access program.
Get an API Key Today
API access ships on the Pro plan and above. The 14-day Pro trial includes API access — generate a test key, point your codegen at the OpenAPI spec, and you can be submitting your first job in well under an hour. If your scale lands you in Business or Enterprise territory, our team will help you with the integration directly.
Ship Print Into Your Stack
Free 14-day Pro trial — no credit card. Generate test and live API keys from your dashboard the moment you sign up.
Start Pro Trial Free →