One API to send labels to any thermal printer. Ship faster with ZPL, templates, or images — 6 lines of code.
# Print a shipping label in one call curl https://labelinn.com/v1/print/jobs \ -H "Authorization: Bearer sk_live_xxx" \ -H "Content-Type: application/json" \ -d '{"printer_id":"abc","payload_type":"template", "design_id":"tmpl_shipping", "data":{"name":"Jane Doe","order":"ORD-4521"}}'
From raw ZPL to visual templates — one unified API. New here? Start with the label printing API overview.
ZPL, ESC/POS, TSPL, SLCS — Zebra, TSC, Bixolon, Honeywell, Brother and more. TCP, USB, and Bluetooth.
Submit up to 100 labels in a single API call. Perfect for order fulfillment and warehouse operations.
Design once in the LabelInn app, fill with data via API. Variables, barcodes, images — all dynamic.
Render any template with data and get a PNG/PDF preview. Verify labels before committing to paper.
Get notified on job completion, failures, printer status changes, and low supply alerts.
Push XML, CSV, JSON, or TSV from any ERP/WMS. Auto-parse, map fields to labels, and print — one API call.
Track API calls, print volumes, and endpoint breakdown. See your usage in real-time.
Use sk_test_ keys to simulate everything without physical prints. Full API parity.
OpenAPI spec + ai-plugin.json manifest. ChatGPT, Claude, and Copilot can discover and use your printing setup.
SHA-256 key hashing, HMAC webhook signatures, SSRF protection, and per-key scoping down to
the individual action — designs:read vs designs:write.
Local LAN API on port 6631. Print via USB/TCP without internet — offline queue syncs back automatically.
Discover USB, network, and Bluetooth printers via API. Trigger scans on remote devices and add printers to your fleet in one flow.
Get started in your language with type-safe, idiomatic client libraries.
npm install labelinn
pip install labelinn
dotnet add package LabelInn
go get github.com/labelinn/labelinn-go
Three concrete steps. The path from a fresh account to a thermal printer humming.
Sign up for a free 14-day Pro trial — no credit card. Open Settings → API Keys in the dashboard, generate a key. Use sk_test_* for sandbox, sk_live_* for production.
REST API — for ERPs, WMSes, custom dashboards. Submit jobs, query the fleet, subscribe to webhooks.
MCP Server — for Claude, Cursor, Copilot, or any AI agent. Natural-language printing.
Edge Server — for offline LAN printing without cloud round-trips.
Submit a print job with the saved design ID and your printer ID. Watch the printer come alive within 2–4 seconds.
Printing is physical and asynchronous. These four cover almost every integration that looks correct in testing and misbehaves in production — worth reading whether you are writing the code yourself or having an AI agent write it.
1. 201 Created does not mean
“printed”. The response comes back as soon as the job is queued; the
label is rendered and printed afterwards by the customer’s own device. Render and
hardware errors therefore never appear in the create response — only in the job.
Poll GET /v1/print/jobs/{id} every ~2 s until status is
completed, failed or cancelled. A job you never poll
is a failure you will never see.
2. A retry needs a new idempotency key.
X-Idempotency-Key caches the response for 24 h, so replaying a key returns the
original job and prints nothing — that is what protects you from double labels on a network
retry. The trap: after a job comes back failed, reusing the same key returns
that failed job instead of reprinting, so a naive retry loop leaves the row permanently
unprinted. Put an attempt counter in the key:
erp:<order>-<line>:<attempt>.
3. Check the printer before you send. A job
aimed at an offline printer sits in queued indefinitely. Call
GET /v1/fleet/printers first: the target needs is_online: true
and cloud_print_enabled: true — the latter is switched on by the
customer in the desktop app and cannot be enabled through the API.
4. Ask the design what fields it wants. Do
not guess variable names. GET /v1/designs/{id}/variables returns the exact keys
plus a ready-made example_payload. Unknown keys in data are
ignored silently, which looks exactly like a binding bug.
Many labels at once: data
accepts an array of rows (max 1000) — one row renders one label, which is how serial
numbers and per-row values work. copies repeats the whole job instead. Use the
array for different labels, copies for N identical ones.
Mirroring an ERP or database: keep the “printed” state in a table you own rather than writing into the source system’s own schema — that is what breaks ERP vendor support contracts. Match on a stable row key and reuse that key in the idempotency header above.
The same guidance is machine-readable in the OpenAPI spec, so an agent that reads the spec gets it without being told.
API key (Bearer) — the default for code. Send
Authorization: Bearer sk_live_xxx on every request. This is what all four
official SDKs use.
OAuth 2.0 — for no-code connectors (Make,
Zapier) so your users never copy a key by hand. Authorization-code flow with optional
S256 PKCE; client_credentials is also accepted with the API key passed as
client_secret.
The issued access_token is a
long-lived LabelInn API key, so expires_in and refresh_token are
deliberately omitted (RFC 6749 §5.1) — treat the token as non-expiring rather
than attempting a refresh.
Every key carries a scope list, chosen when you create it in
Settings → API Keys and editable afterwards without rotating
the secret. A scope is either a bare resource or resource:action:
The action is derived from the HTTP method, so
“may read designs but never create one” works on every endpoint. Resources:
print, fleet, designs, webhooks,
usage, connect, audit, workflows,
rules, sites, analytics, render.
Scope an agent key tightly. A key you hand to
an AI agent or a third-party integration should rarely carry print — the
Design only preset gives full authoring with no ability to put ink on media. A key
that cannot print is not shown printing tools over MCP at all, so the agent never plans
around a capability it does not have.
A request outside a key's scopes returns
403 INSUFFICIENT_PERMISSIONS with a required_scope field naming
exactly the scope that would allow it. Keys created before scopes were split by action hold
bare resource scopes and are unaffected.
You can also set a per-key rate ceiling in requests per minute, at or below your plan's limit — useful for capping what a single integration can do.
Plug LabelInn into any Model Context Protocol client. AI agents call your printers with structured tools, not glue code.
print_label, print_zpl, batch_print, list_printers, design CRUD, render previews, audit, edge rules — the full LabelInn surface as MCP tools.
Browse labelinn://printers, labelinn://designs, labelinn://usage, labelinn://jobs/recent — read-only data the agent can pull on demand.
Runs on your machine via npx @labelinn/mcp-server. Prompts and template data never leave your computer; only LLM calls go to your provider.
{ "mcpServers": { "labelinn": { "command": "npx", "args": ["-y", "@labelinn/mcp-server"], "env": { "LABELINN_API_KEY": "sk_live_..." } } } }
Print directly to USB and network printers over your LAN — zero cloud round-trips, works offline.
GET /local/v1/health — Server statusPOST /local/v1/print/jobs — Submit a print jobGET /local/v1/jobs/{id} — Poll job statusGET /local/v1/fleet/printers — List printersPOST /local/v1/fleet/discover — Auto-discover printersGET /local/v1/fleet/discover/{id} — Poll discovery// 1. Discover the Edge Server on your LAN
const health = await fetch('http://192.168.1.100:6631/local/v1/health');
// { status: "ok", server: "LabelInn Edge Server", mode: "hybrid", ... }
// 2. List connected printers
const printers = await fetch('http://192.168.1.100:6631/local/v1/fleet/printers', {
headers: { 'Authorization': 'Bearer YOUR_EDGE_TOKEN' }
});
// { printers: [{ id: "usb_zebra_01", name: "ZD420", ... }], count: 1 }
// 3. Print a label — returns instantly (HTTP 202)
const job = await fetch('http://192.168.1.100:6631/local/v1/print/jobs', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_EDGE_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
printerId: 'usb_zebra_01',
payloadType: 'zpl',
payloadData: '^XA^FO50,50^ADN,36,20^FDHello Edge^FS^XZ',
copies: 1
})
});
// { jobId: "abc-123", status: "accepted" }
// 4. Poll for result
const result = await fetch('http://192.168.1.100:6631/local/v1/jobs/abc-123', {
headers: { 'Authorization': 'Bearer YOUR_EDGE_TOKEN' }
});
// { jobId: "abc-123", success: true, printedLabels: 1 }
Scan for printers on any device running LabelInn. USB, mDNS, network scan, and ZPL validation — all from one API call.
POST /v1/fleet/discoverGET /v1/fleet/discover/{sessionId}POST /v1/fleet/discover/{sessionId}/add
POST /local/v1/fleet/discoverGET /local/v1/fleet/discover/{sessionId}
// ── Cloud API: Discover printers on a remote device ──
// 1. Start a discovery session (target a specific device or any online device)
const session = await fetch('https://labelinn.com/v1/fleet/discover', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({ device_id: 'dev_warehouse_pc' })
});
// { data: { session_id: "abc123", status: "pending" } }
// 2. Poll until discovery is complete
const results = await fetch('https://labelinn.com/v1/fleet/discover/abc123', {
headers: { 'Authorization': 'Bearer sk_live_xxx' }
});
// { data: { status: "complete", printers: [
// { name: "ZD420", address: "192.168.1.50", brand: "ZEBRA", is_thermal: true },
// { name: "Brother QL-820", address: "USB001", connection_type: "usb" }
// ], count: 2 } }
// 3. Add a discovered printer to your fleet
const printer = await fetch('https://labelinn.com/v1/fleet/discover/abc123/add', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify({ address: '192.168.1.50', name: 'Warehouse Zebra #3' })
});
// { data: { id: "prt_a1b2c3d4e5f6", name: "Warehouse Zebra #3", status: "registered" } }
// 4. Now print to it!
await fetch('https://labelinn.com/v1/print/jobs', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_live_xxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
printer_id: 'prt_a1b2c3d4e5f6',
payload_type: 'template',
design_id: 'tmpl_shipping',
data: { name: 'Jane Doe', order: 'ORD-4521' }
})
});
Universal enterprise data ingestion — connect any data source to label printing.
// 1. Test-parse your data first (no storage, no cost)
const preview = await fetch('https://labelinn.com/v1/connect/test-parse', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_test_YOUR_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
payload: 'name,sku,qty,price\nWidget,SKU-001,50,9.99\nGadget,SKU-002,30,14.50',
format: 'csv'
})
});
// { schema: [{path:"name",type:"string"}, {path:"qty",type:"number"}, ...], records_preview: [...] }
// 2. Push real data & print labels — 2 API calls
const result = await client.connect.ingest({
source_id: "conn_sap_orders",
payload: xmlFromSAP,
format: "xml",
config: { repeatPath: "IDOC.E1EDP01" }
});
await client.connect.sources.print("conn_sap_orders", {
printer_id: "prt_warehouse_01",
design_id: "dsg_shipping_label",
ingest_id: result.data.ingest_id
});
Connect LabelInn to your existing stack — code-free.
128 operations across 16 categories — every backend route, machine-readable
via OpenAPI 3.0.3 spec v2.0.0.
AI agents discover this at https://labelinn.com/.well-known/ai-plugin.json.
Pull what you printed: every job with its resolved element values and origin, the rendered PNG, the exact ZPL/TSPL sent to the device, and the request body that caused it — each sha256-chained and verifiable.
API access is included with Pro and Enterprise plans.
Create an account, generate an API key, send your first print job.
REST API, OpenAPI, webhooks, files, databases and reviewed custom contracts













