The Stripe for
Physical Printing
Connect your ERP, e-commerce platform, or any system to physical label printers with a simple REST API. Design labels visually, bind variables to your data, and print from anywhere in the world.
Get Started βhttps://labelinn.com/v1
How It Works
LabelInn bridges the gap between cloud APIs and physical printers. Your system sends HTTP requests β our desktop relay app converts them to printer commands and sends to hardware.
Your System sends an API request
ERP, e-commerce, Zapier, custom app β anything that can make HTTP calls. Send a print job with your label design ID and variable data.
Cloud Functions process the request
Firebase Cloud Functions validate your API key, check rate limits, resolve the design, apply variable data, and write a job to Firestore.
LabelInn Desktop picks up the job
The Cloud Print Relay running on your desktop/server detects new jobs, renders the design with your data, and converts it to printer language (ZPL, TPCL, ESC/POS).
Label prints on your physical printer
The rendered label is sent directly to your printer via TCP, USB, or Bluetooth. Job status updates in real-time. Webhooks fire on completion.
403 PLAN_NO_API error on every request.
Quick Start
Get your first label printed in under 5 minutes.
0. Prerequisites
Before you start, make sure you have:
- A LabelInn account with Pro, Enterprise, or Trial plan
- The LabelInn Desktop App installed and running on a PC on the same network as your printers
- At least one printer added and showing online in the app
1. Get your API key
Open the LabelInn desktop app β Settings β API Keys β Generate New Key. Copy the sk_live_... key β it's only shown once.
2. Make sure a printer is connected
Add a printer in the LabelInn app and ensure it shows as online. Keep the app running (it minimizes to system tray).
3. Find a design to print
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/designs
4. Check what variables the design expects
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/designs/DESIGN_ID/variables
# Response includes an example_payload you can copy-paste:
# {
# "variables": [{"key": "product_name", ...}, {"key": "sku", ...}],
# "example_payload": {
# "data": { "product_name": "<text>", "sku": "<text>" }
# }
# }
5. Print it!
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "YOUR_PRINTER_ID",
"data": {
"product_name": "Organic Coffee Beans",
"sku": "COF-001-ORG"
},
"copies": 2
}' \
https://labelinn.com/v1/designs/DESIGN_ID/print
6. Track the job
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/print/jobs/JOB_ID
# Status progression: queued β claimed β rendering β printing β completed
Authentication
All API requests require a Bearer token in the Authorization header.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Key Types
| Prefix | Environment | Behavior |
|---|---|---|
| sk_live_* | Production | Jobs are sent to physical printers |
| sk_test_* | Sandbox | Jobs are simulated β no physical prints |
Managing API Keys
API keys are managed through the LabelInn desktop app (Settings β API Keys) or via Firebase callable functions. Keys are SHA-256 hashed at rest β the full key is only shown once at creation.
Errors & Status Codes
All errors return a consistent JSON structure:
{
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid or revoked API key"
}
}
HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Resource created |
| 202 | Accepted (async processing, e.g., render jobs) |
| 400 | Bad request β check your request body |
| 401 | Unauthorized β invalid or missing API key |
| 403 | Forbidden β plan doesn't support API, or insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict β e.g., trying to cancel a non-queued job |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
Error Codes
| Code | HTTP | Description |
|---|---|---|
| MISSING_API_KEY | 401 | No Authorization header provided |
| INVALID_KEY_FORMAT | 401 | Key doesn't start with sk_live_ or sk_test_ |
| INVALID_API_KEY | 401 | Key not found or has been revoked |
| COMPANY_NOT_FOUND | 403 | Company associated with key not found |
| PLAN_NO_API | 403 | Current plan doesn't include API access |
| RATE_LIMIT_EXCEEDED | 429 | Daily request limit exceeded (resets midnight UTC) |
| JOB_NOT_CANCELLABLE | 409 | Job is not in queued state |
Rate Limits
API rate limits are enforced per API key, resetting daily at midnight UTC.
| Plan | Daily Limit | API Access |
|---|---|---|
| Free | 0 | No API access |
| Trial | 100 | Limited testing |
| Starter | 0 | No API access |
| Pro | 2,000 | Full access |
| Enterprise | 50,000 | Full access + priority |
retry_after_seconds telling you when your limit resets.
Print Jobs
Submit, track, cancel, and reprint label print jobs. Jobs are processed by the LabelInn desktop relay connected to your printers.
Submit a new print job. Supports raw ZPL, base64 images, or template-based printing with variable data.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| printer_id | string | Required | Target printer ID |
| payload_type | string | Required | zpl, image, or template |
| payload_data | string | Conditional | ZPL string or base64 PNG (required for zpl/image types). Max 500KB. |
| design_id | string | Conditional | Design template ID (required for template type) |
| data | object | object[] | Optional | Variable values. Single object for one label, array for batch. |
| job_name | string | Optional | Display name for the job |
| copies | number | Optional | Number of copies per label (1β1000, default: 1) |
| media_width_mm | number | Optional | Override media width in mm |
| media_height_mm | number | Optional | Override media height in mm |
Examples
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "printer_abc123",
"payload_type": "template",
"design_id": "design_xyz789",
"data": {
"product_name": "Organic Coffee Beans",
"sku": "COF-001",
"weight": "250g"
},
"copies": 1
}' \
https://labelinn.com/v1/print/jobs
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "printer_abc123",
"payload_type": "zpl",
"payload_data": "^XA^FO50,50^A0N,40,40^FDHello World^FS^XZ"
}' \
https://labelinn.com/v1/print/jobs
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "printer_abc123",
"payload_type": "template",
"design_id": "design_xyz789",
"data": [
{"product_name": "Coffee", "sku": "COF-001"},
{"product_name": "Tea", "sku": "TEA-002"},
{"product_name": "Juice", "sku": "JCE-003"}
],
"copies": 1
}' \
https://labelinn.com/v1/print/jobs
Response 201 Created
{
"data": {
"id": "job_a1b2c3d4e5",
"printer_id": "printer_abc123",
"status": "queued",
"payload_type": "template",
"design_id": "design_xyz789",
"design_name": "Product Label 4x6",
"job_name": "API Job - 2026-03-30T10:15:00Z",
"copies": 1,
"total_labels": 3,
"is_test": false,
"variables_used": ["product_name", "sku"],
"printer_status": "online",
"created_at": "2026-03-30T10:15:00Z",
"message": "Print job queued. 3 labels Γ 1 copy = 3 total prints."
}
}
List print jobs with optional filters and pagination.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| status | string | β | Filter: queued claimed rendering printing completed failed cancelled |
| printer_id | string | β | Filter by printer |
| limit | number | 25 | Results per page (1β100) |
| page_token | string | β | Cursor for next page |
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
"https://labelinn.com/v1/print/jobs?status=completed&limit=10"
Response
{
"data": [
{
"id": "job_a1b2c3d4e5",
"printer_id": "printer_abc123",
"printer_name": "Warehouse Zebra ZT411",
"status": "completed",
"payload_type": "template",
"design_id": "design_xyz789",
"job_name": "Inventory Labels",
"copies": 2,
"total_labels": 6,
"printed_labels": 6,
"is_test": false,
"error_message": null,
"submitted_by": "LabelInn API v1",
"created_at": "2026-03-30T10:15:00Z",
"completed_at": "2026-03-30T10:15:08Z"
}
],
"pagination": {
"has_more": true,
"next_page_token": "cursor_f6g7h8i9"
}
}
Get the status and details of a specific print job.
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/print/jobs/job_a1b2c3d4e5
Job Status Flow
Cancel a queued print job. Only jobs in queued state can be cancelled.
curl -X DELETE \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/print/jobs/job_a1b2c3d4e5
Response
{
"data": { "id": "job_a1b2c3d4e5", "status": "cancelled" }
}
Reprint a previous job with optional overrides for printer, copies, or variable data.
Request Body (all fields optional)
| Field | Type | Description |
|---|---|---|
| printer_id | string | Override target printer |
| copies | number | Override copy count |
| data | object | object[] | Override variable data (template jobs only) |
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"copies": 3, "printer_id": "printer_backup_01"}' \
https://labelinn.com/v1/print/jobs/job_a1b2c3d4e5/reprint
Designs
Create and manage label designs programmatically. Add elements (text, barcodes, images, shapes), bind variables to elements, then print with dynamic data.
List all designs, optionally filtered by category.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| category | string | β | Filter by category (e.g., shipping, product) |
| limit | number | 25 | Results per page (1β100) |
| page_token | string | β | Pagination cursor |
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
"https://labelinn.com/v1/designs?category=shipping"
Create a new blank label design. Add elements after creation.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Design name (max 256 chars) |
| description | string | Optional | Description (max 1024 chars) |
| category | string | Optional | Category tag (default: custom) |
| size | object | Optional | {w, h} in mm (default: 100Γ150) |
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Shipping Label 4x6",
"description": "E-commerce shipping label with tracking",
"category": "shipping",
"size": {"w": 100, "h": 150}
}' \
https://labelinn.com/v1/designs
Get a design with all its elements and variable definitions.
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/designs/design_xyz789
Update design metadata (name, description, category, size).
curl -X PUT \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Label Name", "category": "product"}' \
https://labelinn.com/v1/designs/design_xyz789
Permanently delete a design and all its elements.
curl -X DELETE \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/designs/design_xyz789
Design Elements
Elements are the building blocks of a label design β text fields, barcodes, images, shapes, and more. Each element can be bound to a variable for dynamic data.
Add Element
| Field | Type | Required | Description |
|---|---|---|---|
| type | string | Required | Element type (see supported types below) |
| position | object | Optional | {x, y} in mm from top-left |
| size | object | Optional | {w, h} in mm |
| z_index | number | Optional | Stacking order |
| rotation | number | Optional | Rotation in degrees |
| variable | string | Optional | Variable key to bind (enables dynamic data) |
| properties | object | Optional | Type-specific properties |
Update Element
Update any element property β position, size, rotation, variable binding, or type-specific properties.
Delete Element
Remove an element from a design.
Element Types Reference
Full reference for all supported element types and their properties.
Text Element
Rich text with fonts, colors, alignment, and variable binding. The most common element for dynamic labels.
{
"type": "text",
"position": {"x": 10, "y": 10},
"size": {"w": 80, "h": 12},
"variable": "product_name",
"properties": {
"text": "Default Product Name",
"font": "Arial",
"font_size": 14,
"color": "#000000",
"alignment": "left",
"bold": true
}
}
| Property | Type | Default | Description |
|---|---|---|---|
| text | string | "" | Default/static text content |
| font | string | "Arial" | Font family name |
| font_size | number | 14 | Font size in points |
| color | string | "#000000" | Hex color |
| alignment | string | "left" | left, center, right, justify |
| vertical_alignment | string | "top" | top, middle, bottom |
| bold | boolean | false | Bold text |
| italic | boolean | false | Italic text |
| underline | boolean | false | Underlined text |
| character_spacing | number | 0 | Space between characters |
| line_spacing | number | 1.0 | Line height multiplier |
| text_case | string | "none" | none, uppercase, lowercase, capitalize |
| background_color | string | "#FFFFFF" | Background fill color |
| background_transparent | boolean | true | Whether background is transparent |
| corner_radius | number | 0 | Border corner radius |
| stroke_color | string | "#000000" | Border stroke color |
| stroke_width | number | 0 | Border stroke width |
Barcode Element
1D and 2D barcodes including QR codes, Code 128, EAN-13, DataMatrix, and more.
{
"type": "barcode",
"position": {"x": 60, "y": 20},
"size": {"w": 30, "h": 30},
"variable": "tracking_url",
"properties": {
"data": "https://track.example.com/default",
"barcode_type": "qrcode",
"qr_error_correction": "medium"
}
}
| Property | Type | Default | Description |
|---|---|---|---|
| data | string | "" | Barcode data/value |
| barcode_type | string | "code128" | code128 code39 code93 ean13 ean8 upca upce qrcode datamatrix pdf417 aztec |
| color | string | "#000000" | Bar/module color |
| background_color | string | "#FFFFFF" | Background color |
| show_text | string | "bottom" | bottom, top, none β human-readable text position |
| text_font | string | "Courier" | Human-readable text font |
| qr_error_correction | string | "low" | QR error correction: low medium high ultra |
Image Element
{
"type": "image",
"position": {"x": 5, "y": 5},
"size": {"w": 25, "h": 25},
"properties": {
"image_source": "https://example.com/logo.png",
"source_type": "static",
"opacity": 1.0,
"grayscale": false
}
}
Shape Element
Geometric shapes β rectangle, ellipse, polygon, star.
{
"type": "shape",
"position": {"x": 0, "y": 0},
"size": {"w": 100, "h": 150},
"properties": {
"shape_type": "rectangle",
"fill_color": "#FFFFFF",
"stroke": {"color": "#000000", "width": 1.0, "dashStyle": "solid"}
}
}
Line Element
{
"type": "line",
"properties": {
"start_point": {"x": 5, "y": 50},
"end_point": {"x": 95, "y": 50},
"stroke": {"color": "#000000", "width": 0.5, "dashStyle": "dashed"}
}
}
SVG Element
{
"type": "svg",
"position": {"x": 5, "y": 5},
"size": {"w": 20, "h": 20},
"properties": {
"svg_source": "https://example.com/icon.svg",
"color_mode": "color",
"fit": "contain"
}
}
Items List Element
A dynamic list for order items, inventory counts, etc. Binds to an array variable.
{
"type": "itemsList",
"position": {"x": 5, "y": 60},
"size": {"w": 90, "h": 80},
"variable": "order_items",
"properties": {
"template": {"template": "{name} x{quantity}", "separator": "newLine"},
"font": "Arial", "font_size": 10
}
}
HTML Element
Embed custom HTML/CSS for complex layouts.
{
"type": "html",
"position": {"x": 0, "y": 0},
"size": {"w": 100, "h": 150},
"properties": {
"html_content": "<div class='label'>Custom HTML...</div>",
"css_content": ".label { padding: 8px; }",
"thermal_mode": true
}
}
List all variables in a design with their types and an auto-generated example payload you can copy-paste into print requests.
{
"data": {
"design_id": "design_xyz789",
"variables": [
{"key": "product_name", "element_type": "text", "default_value": "Product Name"},
{"key": "sku", "element_type": "barcode", "default_value": "000000"},
{"key": "weight", "element_type": "text", "default_value": ""}
],
"example_payload": {
"data": {
"product_name": "<text>",
"sku": "<barcode_data>",
"weight": "<text>"
}
}
}
}
Variable Binding
Variables are the bridge between your data and the label design. When you add a variable field to an element, that element's content becomes dynamic.
How it works
- Design time: Add an element with
"variable": "product_name" - Print time: Send
"data": {"product_name": "Organic Coffee"} - Render: The element's text/barcode data is replaced with your value
Variable Resolution Order
When printing, variable values are resolved in this order:
- Direct match from
dataobject βdata["product_name"] - Integration data sources (if configured in the design)
- Default value from the element's
properties.text/properties.data
GET /v1/designs/:id/variables to discover what variables a design expects. The response includes an example_payload you can copy-paste.
Example: Full workflow
# Create design
curl -X POST -H "Authorization: Bearer sk_live_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Product Label", "size": {"w": 80, "h": 50}}' \
https://labelinn.com/v1/designs
# Add text element bound to "product_name"
curl -X POST -H "Authorization: Bearer sk_live_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "text",
"position": {"x": 5, "y": 5},
"size": {"w": 70, "h": 10},
"variable": "product_name",
"properties": {"text": "Product Name", "font_size": 16, "bold": true}
}' \
https://labelinn.com/v1/designs/DESIGN_ID/elements
# Add barcode element bound to "sku"
curl -X POST -H "Authorization: Bearer sk_live_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "barcode",
"position": {"x": 5, "y": 20},
"size": {"w": 70, "h": 25},
"variable": "sku",
"properties": {"barcode_type": "code128", "show_text": "bottom"}
}' \
https://labelinn.com/v1/designs/DESIGN_ID/elements
curl -X POST -H "Authorization: Bearer sk_live_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "printer_123",
"data": [
{"product_name": "Organic Coffee", "sku": "COF-001"},
{"product_name": "Green Tea", "sku": "TEA-002"},
{"product_name": "Orange Juice", "sku": "JCE-003"}
]
}' \
https://labelinn.com/v1/designs/DESIGN_ID/print
Clone a design including all elements. Optionally rename or recategorize.
Request Body (all fields optional)
| Field | Type | Description |
|---|---|---|
| name | string | New name (default: "Original Name (Copy)") |
| description | string | New description |
| category | string | New category |
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Shipping Label v2"}' \
https://labelinn.com/v1/designs/design_xyz789/clone
Queue a render preview β generates a PNG image of the label with your variable data applied.
Request Body
| Field | Type | Default | Description |
|---|---|---|---|
| data | object | object[] | β | Variable values to render |
| format | string | "png" | Output format |
| width | number | 800 | Output width in pixels (100β4096) |
Response 202 Accepted
{
"data": {
"render_id": "render_abc789",
"design_id": "design_xyz789",
"status": "queued",
"message": "Render job queued. Poll GET /v1/designs/renders/:render_id for status."
}
}
Print a design with variable data β the most common endpoint. This is a shortcut that creates a template print job for this design.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| printer_id | string | Required | Target printer ID |
| data | object | object[] | Optional | Variable values (single or array for batch) |
| job_name | string | Optional | Job display name |
| copies | number | Optional | Copies per label (default: 1) |
| media_width_mm | number | Optional | Override media width |
| media_height_mm | number | Optional | Override media height |
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "printer_abc123",
"data": [
{"product_name": "Coffee Beans", "sku": "COF-001", "weight": "250g"},
{"product_name": "Green Tea", "sku": "TEA-002", "weight": "100g"},
{"product_name": "Orange Juice", "sku": "JCE-003", "weight": "1L"}
],
"copies": 2
}' \
https://labelinn.com/v1/designs/design_xyz789/print
Fleet Management
Monitor your printer fleet β check status, supplies, and connection details.
List all printers registered to your account with optional filters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| status | string | Filter: online, offline, unknown |
| type | string | Filter: zebra, intermec, sato, brother, custom |
| connection | string | Filter: tcp, bluetooth, serial, usb |
curl -H "Authorization: Bearer sk_live_YOUR_KEY" \
"https://labelinn.com/v1/fleet/printers?status=online"
Response
{
"data": [
{
"id": "printer_abc123",
"name": "Warehouse Zebra ZT411",
"model": "Zebra ZT411",
"type": "ZEBRA",
"connection": "tcp",
"address": "192.168.1.100",
"port": 9100,
"is_thermal": true,
"status": "online",
"is_online": true,
"cloud_print_enabled": true,
"last_heartbeat": "2026-03-30T10:45:00Z"
}
],
"total": 1
}
Get full printer details including supplies, telemetry, and recent print activity.
{
"data": {
"id": "printer_abc123",
"name": "Warehouse Zebra ZT411",
"model": "Zebra ZT411",
"type": "ZEBRA",
"connection": "tcp",
"address": "192.168.1.100",
"port": 9100,
"is_thermal": true,
"status": "online",
"is_online": true,
"cloud_print_enabled": true,
"last_heartbeat": "2026-03-30T10:45:00Z",
"supplies": [
{"name": "Ribbon", "level": 85, "type": "ribbon", "is_warning": false},
{"name": "Media", "level": 12, "type": "media", "is_warning": true}
],
"last_media": {
"width_mm": 100,
"height_mm": 150,
"type": "thermal"
},
"last_print_job": {
"job_name": "Inventory Labels #4521",
"timestamp": "2026-03-30T10:40:15Z"
}
}
}
Lightweight status check β just online/offline and heartbeat timing.
{
"data": {
"id": "printer_abc123",
"status": "online",
"is_online": true,
"last_heartbeat": "2026-03-30T10:45:00Z",
"seconds_since_heartbeat": 45,
"cloud_print_enabled": true
}
}
Webhooks
Subscribe to real-time events β get notified when jobs complete, printers go offline, or supplies run low. No polling needed.
Subscribe to webhook events. Your endpoint must be HTTPS.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Required | HTTPS endpoint URL (no localhost/private IPs) |
| events | string[] | Required | Events to subscribe to (see events reference) |
| description | string | Optional | Description (max 256 chars) |
curl -X POST \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/labelinn",
"events": ["print.job.completed", "print.job.failed", "printer.supply.low"],
"description": "Order fulfillment notifications"
}' \
https://labelinn.com/v1/webhooks
Response 201 Created
{
"data": {
"id": "wh_abc123xyz",
"url": "https://your-server.com/webhooks/labelinn",
"events": ["print.job.completed", "print.job.failed", "printer.supply.low"],
"secret": "whsec_abcdef123456...",
"description": "Order fulfillment notifications",
"warning": "Store the secret securely. It is used to verify webhook signatures."
}
}
whsec_...) is only shown once at creation. Use it to verify webhook signatures.
List all active webhook subscriptions.
{
"data": [
{
"id": "wh_abc123xyz",
"url": "https://your-server.com/webhooks/labelinn",
"events": ["print.job.completed", "print.job.failed"],
"is_active": true,
"description": "Order fulfillment",
"failure_count": 0,
"last_delivered_at": "2026-03-30T10:50:00Z",
"created_at": "2026-03-16T14:22:00Z"
}
]
}
Remove a webhook subscription. Events will immediately stop being delivered.
curl -X DELETE \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
https://labelinn.com/v1/webhooks/wh_abc123xyz
Webhook Events Reference
All available events you can subscribe to.
| Event | Fires When |
|---|---|
| print.job.completed | A print job finishes successfully |
| print.job.failed | A print job fails (printer error, timeout, etc.) |
| print.job.cancelled | A job is cancelled via API or app |
| printer.status.changed | A printer goes online or offline |
| printer.supply.low | Ink, ribbon, or media drops below 15% |
Webhook Delivery Format
LabelInn sends a POST request to your URL with these headers:
| Header | Description |
|---|---|
| Content-Type | application/json |
| X-LabelInn-Signature | sha256=<HMAC hex digest> |
| X-LabelInn-Event | Event type (e.g., print.job.completed) |
| X-LabelInn-Delivery | Unique delivery ID (UUID) |
| User-Agent | LabelInn-Webhooks/1.0 |
Event Payload Examples
{
"event": "print.job.completed",
"timestamp": "2026-03-30T10:50:00Z",
"data": {
"job_id": "job_a1b2c3d4e5",
"printer_id": "printer_abc123",
"printer_name": "Warehouse Zebra",
"status": "completed",
"job_name": "Inventory Labels",
"copies": 2,
"total_labels": 6,
"printed_labels": 6,
"completed_at": "2026-03-30T10:49:50Z"
}
}
{
"event": "printer.status.changed",
"timestamp": "2026-03-30T11:00:00Z",
"data": {
"printer_id": "printer_abc123",
"printer_name": "Warehouse Zebra",
"previous_status": "offline",
"current_status": "online",
"last_heartbeat": "2026-03-30T10:59:45Z"
}
}
{
"event": "printer.supply.low",
"timestamp": "2026-03-30T11:05:00Z",
"data": {
"printer_id": "printer_abc123",
"printer_name": "Warehouse Zebra",
"supply_name": "Media",
"supply_type": "media",
"level": 12
}
}
Webhook Signature Verification
Always verify webhook signatures to ensure the request is genuinely from LabelInn. The signature is an HMAC-SHA256 digest of the raw request body using your webhook secret.
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(JSON.stringify(body))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your Express handler:
app.post('/webhooks/labelinn', (req, res) => {
const sig = req.headers['x-labelinn-signature'];
if (!verifyWebhook(req.body, sig, process.env.LABELINN_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = req.headers['x-labelinn-event'];
console.log(`Received ${event}:`, req.body.data);
// Process the event...
res.status(200).send('OK');
});
import hmac, hashlib, json
def verify_webhook(body: dict, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
json.dumps(body).encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler:
@app.route('/webhooks/labelinn', methods=['POST'])
def handle_webhook():
sig = request.headers.get('X-LabelInn-Signature', '')
if not verify_webhook(request.json, sig, os.environ['LABELINN_WEBHOOK_SECRET']):
return 'Invalid signature', 401
event = request.headers.get('X-LabelInn-Event')
print(f'Received {event}:', request.json['data'])
return 'OK', 200
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
bool VerifyWebhook(string body, string signature, string secret)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body));
var expected = "sha256=" + BitConverter.ToString(hash)
.Replace("-", "").ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(signature),
Encoding.UTF8.GetBytes(expected));
}
// In your ASP.NET handler:
[HttpPost("webhooks/labelinn")]
public IActionResult HandleWebhook()
{
var sig = Request.Headers["X-LabelInn-Signature"].ToString();
using var reader = new StreamReader(Request.Body);
var body = reader.ReadToEndAsync().Result;
if (!VerifyWebhook(body, sig, _config["LabelInn:WebhookSecret"]))
return Unauthorized("Invalid signature");
var evt = Request.Headers["X-LabelInn-Event"].ToString();
_logger.LogInformation($"Received {evt}");
return Ok();
}
Data Connect
Universal enterprise data ingestion. Push XML, CSV, JSON, TSV, or NDJSON from any system and print labels directly from your external data. Supports SAP IDoc, flat files, webhooks, and any structured payload up to 5 MB.
Push data in any supported format. Auto-detects JSON, CSV, TSV, XML, and NDJSON. If source_id is omitted, a new connector is auto-created.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| payload | string | Required | Raw data string (CSV, XML, JSON, TSV, or NDJSON) |
| format | string | Optional | Force format: json csv tsv xml ndjson. Auto-detected if omitted. |
| source_id | string | Optional | Existing connector source ID. Omit to auto-create a new source. |
| config | object | Optional | Parser config, e.g. { "repeatPath": "IDOC.E1EDP01" } for XML repeat elements. |
curl -X POST https://labelinn.com/v1/connect/ingest \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"source_id": "conn_abc123",
"payload": "name,sku,qty\nWidget,SKU-001,50\nGadget,SKU-002,30",
"format": "csv"
}'
Response 201 Created
{
"data": {
"source_id": "conn_abc123",
"ingest_id": "ing_xyz789",
"format": "csv",
"record_count": 2,
"schema": [
{ "path": "name", "type": "string", "sample": "Widget" },
{ "path": "sku", "type": "string", "sample": "SKU-001" },
{ "path": "qty", "type": "string", "sample": "50" }
]
}
}
sk_test_*) parse without storing.
Dry-run parse β returns schema, inferred types, and a preview of parsed records without storing anything. Use this to preview how your data will be interpreted before committing to a source. Supports JSON, CSV, TSV, XML (including SAP IDoc), and NDJSON. Format is auto-detected from content, or force it with format.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| payload | string | Required | Raw data string to parse |
| format | string | Optional | Force format: json csv tsv xml ndjson. Auto-detected if omitted. |
| config | object | Optional | Parser-specific config (see format examples below) |
Config Options by Format
| Format | Config Key | Type | Description |
|---|---|---|---|
| csv / tsv | delimiter | string | Force delimiter character (auto-detected: , ; | \t) |
| csv / tsv | hasHeader | boolean | First row is header (default: true) |
| json / ndjson | recordsPath | string | Dot-path to array (e.g. "data.orders"). Auto-detected if omitted. |
| json / ndjson | maxDepth | number | Max nesting depth to flatten (default: 10) |
| xml | repeatPath | string | Dot-path of repeating element (e.g. "IDOC.E1EDP01") |
| xml | includeAttributes | boolean | Include XML attributes as @attr keys (default: true) |
Examples β Try Each Format
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "name,sku,qty,price,in_stock\nWidget,SKU-001,50,9.99,true\nGadget,SKU-002,30,14.50,true\nSprocket,SKU-003,0,7.25,false",
"format": "csv"
}'
{
"data": {
"format": "csv",
"record_count": 3,
"schema": [
{ "path": "name", "type": "string", "sample": "Widget", "label": "Name" },
{ "path": "sku", "type": "string", "sample": "SKU-001", "label": "Sku" },
{ "path": "qty", "type": "number", "sample": "50", "label": "Qty" },
{ "path": "price", "type": "number", "sample": "9.99", "label": "Price" },
{ "path": "in_stock", "type": "boolean", "sample": "true", "label": "In Stock" }
],
"records_preview": [
{ "name": "Widget", "sku": "SKU-001", "qty": "50", "price": "9.99", "in_stock": "true" },
{ "name": "Gadget", "sku": "SKU-002", "qty": "30", "price": "14.50", "in_stock": "true" },
{ "name": "Sprocket", "sku": "SKU-003", "qty": "0", "price": "7.25", "in_stock": "false" }
]
}
}
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "{\"data\":{\"orders\":[{\"id\":\"ORD-1001\",\"customer\":\"Acme Corp\",\"item\":\"Widget\",\"qty\":5,\"ship_date\":\"2026-04-01\"},{\"id\":\"ORD-1002\",\"customer\":\"Globex\",\"item\":\"Gadget\",\"qty\":12,\"ship_date\":\"2026-04-02\"}]}}",
"format": "json",
"config": { "recordsPath": "data.orders" }
}'
{
"data": {
"format": "json",
"record_count": 2,
"schema": [
{ "path": "id", "type": "string", "sample": "ORD-1001", "label": "Id" },
{ "path": "customer", "type": "string", "sample": "Acme Corp", "label": "Customer" },
{ "path": "item", "type": "string", "sample": "Widget", "label": "Item" },
{ "path": "qty", "type": "number", "sample": "5", "label": "Qty" },
{ "path": "ship_date", "type": "date", "sample": "2026-04-01", "label": "Ship Date" }
],
"records_preview": [
{ "id": "ORD-1001", "customer": "Acme Corp", "item": "Widget", "qty": 5, "ship_date": "2026-04-01" },
{ "id": "ORD-1002", "customer": "Globex", "item": "Gadget", "qty": 12, "ship_date": "2026-04-02" }
]
}
}
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "<shipment><package id=\"PKG-001\"><tracking>1Z999AA10123456784</tracking><weight>2.5</weight><destination>New York</destination></package><package id=\"PKG-002\"><tracking>1Z999AA10123456785</tracking><weight>1.2</weight><destination>Chicago</destination></package></shipment>",
"format": "xml",
"config": { "includeAttributes": true }
}'
{
"data": {
"format": "xml",
"record_count": 2,
"schema": [
{ "path": "@id", "type": "string", "sample": "PKG-001", "label": "Id" },
{ "path": "tracking", "type": "string", "sample": "1Z999AA10123456784", "label": "Tracking" },
{ "path": "weight", "type": "number", "sample": "2.5", "label": "Weight" },
{ "path": "destination", "type": "string", "sample": "New York", "label": "Destination" }
],
"records_preview": [
{ "@id": "PKG-001", "tracking": "1Z999AA10123456784", "weight": "2.5", "destination": "New York" },
{ "@id": "PKG-002", "tracking": "1Z999AA10123456785", "weight": "1.2", "destination": "Chicago" }
]
}
}
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "{\"event\":\"order_placed\",\"order_id\":\"ORD-5001\",\"product\":\"Label Roll 4x6\",\"qty\":100}\n{\"event\":\"order_placed\",\"order_id\":\"ORD-5002\",\"product\":\"Thermal Ribbon\",\"qty\":50}\n{\"event\":\"order_shipped\",\"order_id\":\"ORD-5001\",\"product\":\"Label Roll 4x6\",\"qty\":100}",
"format": "ndjson"
}'
{
"data": {
"format": "ndjson",
"record_count": 3,
"schema": [
{ "path": "event", "type": "string", "sample": "order_placed", "label": "Event" },
{ "path": "order_id", "type": "string", "sample": "ORD-5001", "label": "Order Id" },
{ "path": "product", "type": "string", "sample": "Label Roll 4x6", "label": "Product" },
{ "path": "qty", "type": "number", "sample": "100", "label": "Qty" }
],
"records_preview": [
{ "event": "order_placed", "order_id": "ORD-5001", "product": "Label Roll 4x6", "qty": 100 },
{ "event": "order_placed", "order_id": "ORD-5002", "product": "Thermal Ribbon", "qty": 50 },
{ "event": "order_shipped", "order_id": "ORD-5001", "product": "Label Roll 4x6", "qty": 100 }
]
}
}
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "location\tbin\tsku\tqty\nlast_scan\nA-01\tB12\tSKU-001\t50\t2026-03-30\nA-02\tC05\tSKU-002\t30\t2026-03-29\nB-01\tA01\tSKU-003\t120\t2026-03-30",
"format": "tsv"
}'
{
"data": {
"format": "tsv",
"record_count": 3,
"schema": [
{ "path": "location", "type": "string", "sample": "A-01", "label": "Location" },
{ "path": "bin", "type": "string", "sample": "B12", "label": "Bin" },
{ "path": "sku", "type": "string", "sample": "SKU-001", "label": "Sku" },
{ "path": "qty", "type": "number", "sample": "50", "label": "Qty" },
{ "path": "last_scan", "type": "date", "sample": "2026-03-30", "label": "Last Scan" }
],
"records_preview": [
{ "location": "A-01", "bin": "B12", "sku": "SKU-001", "qty": "50", "last_scan": "2026-03-30" },
{ "location": "A-02", "bin": "C05", "sku": "SKU-002", "qty": "30", "last_scan": "2026-03-29" },
{ "location": "B-01", "bin": "A01", "sku": "SKU-003", "qty": "120", "last_scan": "2026-03-30" }
]
}
}
curl -X POST https://labelinn.com/v1/connect/test-parse \
-H "Authorization: Bearer sk_test_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"payload": "<IDOC><EDI_DC40><DOCNUM>0000001234</DOCNUM></EDI_DC40><E1EDP01><MATNR>MAT-001</MATNR><MENGE>100</MENGE><MEINS>PC</MEINS><WERKS>1000</WERKS></E1EDP01><E1EDP01><MATNR>MAT-002</MATNR><MENGE>250</MENGE><MEINS>KG</MEINS><WERKS>2000</WERKS></E1EDP01></IDOC>",
"format": "xml",
"config": { "repeatPath": "IDOC.E1EDP01" }
}'
{
"data": {
"format": "xml",
"record_count": 2,
"schema": [
{ "path": "MATNR", "type": "string", "sample": "MAT-001", "label": "Matnr" },
{ "path": "MENGE", "type": "number", "sample": "100", "label": "Menge" },
{ "path": "MEINS", "type": "string", "sample": "PC", "label": "Meins" },
{ "path": "WERKS", "type": "number", "sample": "1000", "label": "Werks" }
],
"records_preview": [
{ "MATNR": "MAT-001", "MENGE": "100", "MEINS": "PC", "WERKS": "1000" },
{ "MATNR": "MAT-002", "MENGE": "250", "MEINS": "KG", "WERKS": "2000" }
]
}
}
Schema Type Inference
Types are automatically inferred from sampled values:
| Inferred Type | Detection Rule | Example Values |
|---|---|---|
number | All samples pass numeric check | 50, 9.99, -3.14 |
boolean | All samples are true or false | true, false |
date | ISO format or European date patterns | 2026-04-01, 01.04.2026 |
url | Starts with http:// or https:// | https://example.com |
string | Default β everything else | Widget, SKU-001 |
Error Responses
| Status | Code | When |
|---|---|---|
| 400 | MISSING_PAYLOAD | No payload field provided |
| 413 | PAYLOAD_TOO_LARGE | Payload exceeds 5 MB |
| 422 | PARSE_ERROR | Data could not be parsed (malformed input) |
sk_test_* keys with test-parse β they parse without counting against your ingest quota. The response previews up to 10 records, even if your payload contains thousands.
Create a named connector source. Returns a webhook URL you can configure in your ERP/WMS to push data automatically.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Human-readable source name (e.g. "SAP Orders") |
| format | string | Optional | Expected data format: json csv tsv xml ndjson |
| config | object | Optional | Parser config, e.g. { "repeatPath": "IDOC.E1EDP01" } |
curl -X POST https://labelinn.com/v1/connect/sources \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "SAP Orders",
"format": "xml",
"config": { "repeatPath": "IDOC.E1EDP01" }
}'
Response 201 Created
{
"data": {
"id": "conn_abc123",
"name": "SAP Orders",
"format": "xml",
"active": true,
"webhook_url": "https://labelinn.com/v1/connect/ingest",
"webhook_headers": {
"Authorization": "Bearer <your_api_key>",
"X-Source-Id": "conn_abc123"
},
"created_at": "2026-03-30T10:00:00Z"
}
}
List all connector sources. Supports pagination and active/inactive filtering.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| active | boolean | β | Filter by active status |
| limit | number | 25 | Results per page (1β100) |
| page_token | string | β | Cursor for next page |
curl https://labelinn.com/v1/connect/sources?limit=25&active=true \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": [
{
"id": "conn_abc123",
"name": "SAP Orders",
"format": "xml",
"active": true,
"record_count": 1250,
"last_ingest_at": "2026-03-30T09:45:00Z"
}
],
"has_more": false
}
Get a single connector source by ID, including config, schema summary, and webhook details.
curl https://labelinn.com/v1/connect/sources/conn_abc123 \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": {
"id": "conn_abc123",
"name": "SAP Orders",
"format": "xml",
"active": true,
"config": { "repeatPath": "IDOC.E1EDP01" },
"record_count": 1250,
"schema_fields": 8,
"webhook_url": "https://labelinn.com/v1/connect/ingest",
"webhook_headers": {
"Authorization": "Bearer <your_api_key>",
"X-Source-Id": "conn_abc123"
},
"created_at": "2026-03-30T10:00:00Z",
"last_ingest_at": "2026-03-30T09:45:00Z"
}
}
Update a connector source's name, format, config, or active status.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Optional | Updated source name |
| format | string | Optional | Updated expected format |
| config | object | Optional | Updated parser config |
| active | boolean | Optional | Enable or disable the source |
curl -X PUT https://labelinn.com/v1/connect/sources/conn_abc123 \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{ "name": "SAP Orders v2", "active": true }'
Response 200 OK
{
"data": {
"id": "conn_abc123",
"name": "SAP Orders v2",
"format": "xml",
"active": true,
"updated_at": "2026-03-30T11:00:00Z"
}
}
Permanently delete a connector source and all its stored records, schema, and mappings. This action cannot be undone.
curl -X DELETE https://labelinn.com/v1/connect/sources/conn_abc123 \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": {
"id": "conn_abc123",
"deleted": true
}
}
Get the auto-discovered schema for a connector source. Schema is generated from ingested data and shows all detected field paths, types, and sample values.
curl https://labelinn.com/v1/connect/sources/conn_abc123/schema \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": {
"source_id": "conn_abc123",
"fields": [
{ "path": "name", "type": "string", "sample": "Widget" },
{ "path": "sku", "type": "string", "sample": "SKU-001" },
{ "path": "qty", "type": "string", "sample": "50" },
{ "path": "price", "type": "number", "sample": "9.99" }
]
}
}
Retrieve parsed records from a connector source. Use ingest_id to filter records from a specific ingest, or omit to get the latest records.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| ingest_id | string | β | Filter by specific ingest batch |
| limit | number | 25 | Results per page (1β100) |
| page_token | string | β | Cursor for next page |
curl https://labelinn.com/v1/connect/sources/conn_abc123/records?limit=10 \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": [
{ "name": "Widget", "sku": "SKU-001", "qty": "50" },
{ "name": "Gadget", "sku": "SKU-002", "qty": "30" }
],
"total": 2,
"has_more": false
}
Map source data fields to label design variables. Keys are source field paths (from schema), values are label variable names used in your design template.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| mappings | object | Required | Key-value pairs: { "source_field": "label_variable" } |
curl -X PUT https://labelinn.com/v1/connect/sources/conn_abc123/mappings \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"mappings": {
"name": "Product Name",
"sku": "SKU Code",
"qty": "Quantity"
}
}'
Response 200 OK
{
"data": {
"source_id": "conn_abc123",
"mappings": {
"name": "Product Name",
"sku": "SKU Code",
"qty": "Quantity"
},
"updated_at": "2026-03-30T11:30:00Z"
}
}
Retrieve the current field-to-variable mappings for a connector source.
curl https://labelinn.com/v1/connect/sources/conn_abc123/mappings \
-H "Authorization: Bearer sk_live_xxxxx"
Response 200 OK
{
"data": {
"source_id": "conn_abc123",
"mappings": {
"name": "Product Name",
"sku": "SKU Code",
"qty": "Quantity"
}
}
}
Print labels from connector data. Uses stored mappings to bind source fields to label design variables. Optionally override with field_mappings.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| printer_id | string | Required | Target printer ID |
| design_id | string | Required | Label design template ID |
| ingest_id | string | Optional | Specific ingest batch to print. Omit for latest. |
| copies | number | Optional | Copies per label (1β1000, default: 1) |
| field_mappings | object | Optional | Override stored mappings: { "source_field": "label_var" } |
curl -X POST https://labelinn.com/v1/connect/sources/conn_abc123/print \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "prt_abc123",
"design_id": "dsg_shipping",
"ingest_id": "ing_xyz789",
"copies": 2
}'
Response 201 Created
{
"data": {
"jobs_created": 42,
"copies_per_job": 2,
"total_labels": 84,
"job_ids": ["job_001", "job_002"],
"source_id": "conn_abc123"
}
}
format / X-Format header to specify explicitly.
Full reference: See SDK documentation for complete Data Connect examples in Node.js, Python, C#, and Go.
Use Cases & Examples
Real-world integration patterns showing how to use the LabelInn API in production. Each example includes complete, runnable code in multiple languages.
E-Commerce Shipping Labels
Automatically print shipping labels when an order is placed. Pull order data, bind it to a label template, and send to the nearest printer.
// Express webhook handler for new Shopify orders
app.post('/webhooks/shopify-order', async (req, res) => {
const order = req.body;
// 1. Find the nearest online printer
const printersRes = await fetch('https://labelinn.com/v1/fleet/printers?status=online', {
headers: { 'Authorization': 'Bearer sk_live_YOUR_KEY' },
});
const printers = await printersRes.json();
const printer = printers.data[0];
// 2. Print a shipping label with order data
const printRes = await fetch('https://labelinn.com/v1/designs/dsg_shipping_4x6/print', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_id: printer.id,
data: {
customer_name: order.shipping_address.name,
address_line1: order.shipping_address.address1,
city: order.shipping_address.city,
postal_code: order.shipping_address.zip,
country: order.shipping_address.country_code,
order_number: order.name,
carrier: 'UPS Ground',
tracking_number: order.fulfillments?.[0]?.tracking_number || '',
weight: order.total_weight + 'g',
},
copies: 1,
}),
});
const result = await printRes.json();
console.log(`Label printed: ${result.data.id}`);
res.json({ ok: true, job_id: result.data.id });
});
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
API_KEY = 'sk_live_YOUR_KEY'
HEADERS = {'Authorization': f'Bearer {API_KEY}'}
@app.route('/webhooks/shopify-order', methods=['POST'])
def handle_order():
order = request.json
# 1. Find an online printer
printers = requests.get(
'https://labelinn.com/v1/fleet/printers?status=online',
headers=HEADERS,
).json()
printer = printers['data'][0]
# 2. Print the shipping label
result = requests.post(
'https://labelinn.com/v1/designs/dsg_shipping_4x6/print',
headers=HEADERS,
json={
'printer_id': printer['id'],
'data': {
'customer_name': order['shipping_address']['name'],
'address_line1': order['shipping_address']['address1'],
'city': order['shipping_address']['city'],
'postal_code': order['shipping_address']['zip'],
'country': order['shipping_address']['country_code'],
'order_number': order['name'],
'carrier': 'UPS Ground',
'weight': f"{order['total_weight']}g",
},
'copies': 1,
},
).json()
return jsonify({'ok': True, 'job_id': result['data']['id']})
[ApiController]
[Route("webhooks")]
public class OrderWebhookController : ControllerBase
{
private readonly HttpClient _http;
public OrderWebhookController(IHttpClientFactory factory)
{
_http = factory.CreateClient();
_http.DefaultRequestHeaders.Add("Authorization", "Bearer sk_live_YOUR_KEY");
}
[HttpPost("shopify-order")]
public async Task<IActionResult> HandleOrder([FromBody] JsonElement order)
{
// 1. Get online printer
var printersRes = await _http.GetFromJsonAsync<JsonElement>(
"https://labelinn.com/v1/fleet/printers?status=online");
var printerId = printersRes.GetProperty("data")[0].GetProperty("id").GetString();
// 2. Print shipping label
var shipping = order.GetProperty("shipping_address");
var payload = new
{
printer_id = printerId,
data = new
{
customer_name = shipping.GetProperty("name").GetString(),
address_line1 = shipping.GetProperty("address1").GetString(),
city = shipping.GetProperty("city").GetString(),
postal_code = shipping.GetProperty("zip").GetString(),
order_number = order.GetProperty("name").GetString(),
carrier = "UPS Ground"
},
copies = 1
};
var result = await _http.PostAsJsonAsync(
"https://labelinn.com/v1/designs/dsg_shipping_4x6/print", payload);
var job = await result.Content.ReadFromJsonAsync<JsonElement>();
return Ok(new { ok = true, job_id = job.GetProperty("data").GetProperty("id").GetString() });
}
}
curl -X POST https://labelinn.com/v1/designs/dsg_shipping_4x6/print \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "prt_warehouse_01",
"data": {
"customer_name": "Jane Doe",
"address_line1": "123 Main St",
"city": "Istanbul",
"postal_code": "34000",
"country": "TR",
"order_number": "#1042",
"carrier": "YurtiΓ§i Kargo",
"tracking_number": "YK-7829384756"
},
"copies": 1
}'
Warehouse & WMS β Batch Label Printing
Print hundreds of labels in one API call for pick-pack-ship workflows. Use batch mode to send an array of label data and let LabelInn handle the queue.
async function printPickListLabels(pickItems) {
const API_KEY = 'sk_live_YOUR_KEY';
const jobs = pickItems.map(item => ({
data: {
sku: item.sku,
product_name: item.name,
location: item.bin_location,
quantity: String(item.qty),
order_ref: item.order_id,
pick_date: new Date().toISOString().split('T')[0],
},
}));
const response = await fetch('https://labelinn.com/v1/print', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_id: 'prt_warehouse_zebra',
design_id: 'dsg_pick_label',
batch: jobs,
copies: 1,
}),
});
const result = await response.json();
console.log(`Batch: ${result.data.total_labels} labels queued`);
return result;
}
// Example usage
await printPickListLabels([
{ sku: 'SKU-001', name: 'Widget A', bin_location: 'A-12-3', qty: 5, order_id: 'ORD-990' },
{ sku: 'SKU-044', name: 'Gadget B', bin_location: 'C-07-1', qty: 2, order_id: 'ORD-991' },
{ sku: 'SKU-112', name: 'Part C', bin_location: 'B-03-5', qty: 10, order_id: 'ORD-992' },
]);
import requests
from datetime import date
API_KEY = 'sk_live_YOUR_KEY'
def print_pick_labels(pick_items):
jobs = [
{
'data': {
'sku': item['sku'],
'product_name': item['name'],
'location': item['bin_location'],
'quantity': str(item['qty']),
'order_ref': item['order_id'],
'pick_date': date.today().isoformat(),
}
}
for item in pick_items
]
result = requests.post(
'https://labelinn.com/v1/print',
headers={'Authorization': f'Bearer {API_KEY}'},
json={
'printer_id': 'prt_warehouse_zebra',
'design_id': 'dsg_pick_label',
'batch': jobs,
'copies': 1,
},
).json()
print(f"Batch: {result['data']['total_labels']} labels queued")
return result
print_pick_labels([
{'sku': 'SKU-001', 'name': 'Widget A', 'bin_location': 'A-12-3', 'qty': 5, 'order_id': 'ORD-990'},
{'sku': 'SKU-044', 'name': 'Gadget B', 'bin_location': 'C-07-1', 'qty': 2, 'order_id': 'ORD-991'},
])
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk_live_YOUR_KEY");
var pickItems = new[]
{
new { Sku = "SKU-001", Name = "Widget A", Bin = "A-12-3", Qty = 5, Order = "ORD-990" },
new { Sku = "SKU-044", Name = "Gadget B", Bin = "C-07-1", Qty = 2, Order = "ORD-991" },
};
var batch = pickItems.Select(item => new
{
data = new
{
sku = item.Sku,
product_name = item.Name,
location = item.Bin,
quantity = item.Qty.ToString(),
order_ref = item.Order,
pick_date = DateTime.Today.ToString("yyyy-MM-dd"),
}
}).ToArray();
var payload = new { printer_id = "prt_warehouse_zebra", design_id = "dsg_pick_label", batch, copies = 1 };
var response = await client.PostAsJsonAsync("https://labelinn.com/v1/print", payload);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"Batch: {result.GetProperty("data").GetProperty("total_labels")} labels queued");
Food & Nutrition Labels
Generate compliant food labels with ingredient lists, allergens, nutrition facts, and expiration dates β all driven by your product database.
async function printFoodLabel(product) {
const response = await fetch('https://labelinn.com/v1/designs/dsg_food_label/print', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_id: 'prt_production_line',
data: {
product_name: product.name,
ingredients: product.ingredients.join(', '),
allergens: product.allergens.join(', '),
net_weight: product.weight,
calories: String(product.nutrition.calories),
protein: product.nutrition.protein,
carbs: product.nutrition.carbs,
fat: product.nutrition.fat,
production_date: new Date().toISOString().split('T')[0],
expiry_date: product.expiry_date,
batch_number: product.batch,
barcode_value: product.ean13,
},
copies: product.label_count,
}),
});
return response.json();
}
await printFoodLabel({
name: 'Organic Strawberry Jam',
ingredients: ['Strawberries (65%)', 'Cane Sugar', 'Lemon Juice', 'Pectin'],
allergens: [],
weight: '340g',
nutrition: { calories: 250, protein: '0.5g', carbs: '62g', fat: '0.1g' },
expiry_date: '2026-09-15',
batch: 'B-2026-0318',
ean13: '8690000012345',
label_count: 200,
});
import requests
from datetime import date, timedelta
API_KEY = 'sk_live_YOUR_KEY'
def print_food_labels(products):
for product in products:
result = requests.post(
'https://labelinn.com/v1/designs/dsg_food_label/print',
headers={'Authorization': f'Bearer {API_KEY}'},
json={
'printer_id': 'prt_production_line',
'data': {
'product_name': product['name'],
'ingredients': ', '.join(product['ingredients']),
'allergens': ', '.join(product.get('allergens', [])),
'net_weight': product['weight'],
'calories': str(product['nutrition']['calories']),
'protein': product['nutrition']['protein'],
'carbs': product['nutrition']['carbs'],
'fat': product['nutrition']['fat'],
'production_date': date.today().isoformat(),
'expiry_date': (date.today() + timedelta(days=product['shelf_days'])).isoformat(),
'batch_number': product['batch'],
'barcode_value': product['ean13'],
},
'copies': product['label_count'],
},
).json()
print(f" {product['name']}: job {result['data']['id']}")
print_food_labels([{
'name': 'Organic Strawberry Jam',
'ingredients': ['Strawberries (65%)', 'Cane Sugar', 'Lemon Juice', 'Pectin'],
'weight': '340g',
'nutrition': {'calories': 250, 'protein': '0.5g', 'carbs': '62g', 'fat': '0.1g'},
'shelf_days': 180, 'batch': 'B-2026-0318', 'ean13': '8690000012345', 'label_count': 200,
}])
curl -X POST https://labelinn.com/v1/designs/dsg_food_label/print \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "prt_production_line",
"data": {
"product_name": "Organic Strawberry Jam",
"ingredients": "Strawberries (65%), Cane Sugar, Lemon Juice, Pectin",
"net_weight": "340g",
"calories": "250",
"protein": "0.5g",
"carbs": "62g",
"fat": "0.1g",
"production_date": "2026-03-18",
"expiry_date": "2026-09-15",
"batch_number": "B-2026-0318",
"barcode_value": "8690000012345"
},
"copies": 200
}'
ERP Integration β SAP, Oracle, Odoo
Connect your ERP to LabelInn via Data Connect. Push orders as XML/JSON, map fields to label variables, and automate printing.
const API_KEY = 'sk_live_YOUR_KEY';
const HEADERS = { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' };
// Step 1: Create a connector source for SAP
const source = await fetch('https://labelinn.com/v1/connect/sources', {
method: 'POST', headers: HEADERS,
body: JSON.stringify({ name: 'SAP Delivery Notes', format: 'xml', config: { repeatPath: 'IDOC.E1EDP01' } }),
}).then(r => r.json());
// Step 2: Map SAP fields β label variables
await fetch(`https://labelinn.com/v1/connect/sources/${source.data.id}/mappings`, {
method: 'PUT', headers: HEADERS,
body: JSON.stringify({
mappings: { 'VBELN': 'delivery_number', 'MATNR': 'material_code', 'MAKTX': 'description', 'LFIMG': 'quantity' },
}),
});
// Step 3: Ingest IDoc XML (SAP calls this webhook automatically)
const ingest = await fetch('https://labelinn.com/v1/connect/ingest', {
method: 'POST',
headers: { ...HEADERS, 'X-Source-Id': source.data.id },
body: JSON.stringify({ payload: sapIdocXmlString, format: 'xml' }),
}).then(r => r.json());
// Step 4: Print labels from ingested data
const result = await fetch(`https://labelinn.com/v1/connect/sources/${source.data.id}/print`, {
method: 'POST', headers: HEADERS,
body: JSON.stringify({
printer_id: 'prt_shipping_dock', design_id: 'dsg_delivery_note',
ingest_id: ingest.data.ingest_id, copies: 1,
}),
}).then(r => r.json());
console.log(`Printed ${result.data.total_labels} delivery labels`);
import requests
API_KEY = 'sk_live_YOUR_KEY'
HEADERS = {'Authorization': f'Bearer {API_KEY}'}
BASE = 'https://labelinn.com/v1'
# Step 1: Create SAP connector source
source = requests.post(f'{BASE}/connect/sources', headers=HEADERS, json={
'name': 'SAP Delivery Notes', 'format': 'xml', 'config': {'repeatPath': 'IDOC.E1EDP01'},
}).json()
source_id = source['data']['id']
# Step 2: Map SAP fields to label variables
requests.put(f'{BASE}/connect/sources/{source_id}/mappings', headers=HEADERS, json={
'mappings': {'VBELN': 'delivery_number', 'MATNR': 'material_code', 'MAKTX': 'description', 'LFIMG': 'quantity'},
})
# Step 3: Ingest IDoc XML
ingest = requests.post(f'{BASE}/connect/ingest', headers={**HEADERS, 'X-Source-Id': source_id},
json={'payload': sap_idoc_xml, 'format': 'xml'}).json()
# Step 4: Print labels
result = requests.post(f'{BASE}/connect/sources/{source_id}/print', headers=HEADERS, json={
'printer_id': 'prt_shipping_dock', 'design_id': 'dsg_delivery_note',
'ingest_id': ingest['data']['ingest_id'], 'copies': 1,
}).json()
print(f"Printed {result['data']['total_labels']} delivery labels")
# 1. Create a connector source
curl -X POST https://labelinn.com/v1/connect/sources \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"SAP Delivery Notes","format":"xml","config":{"repeatPath":"IDOC.E1EDP01"}}'
# 2. Map fields (use source_id from step 1)
curl -X PUT https://labelinn.com/v1/connect/sources/conn_abc123/mappings \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"mappings":{"VBELN":"delivery_number","MATNR":"material_code","LFIMG":"quantity"}}'
# 3. Ingest XML data
curl -X POST https://labelinn.com/v1/connect/ingest \
-H "Authorization: Bearer sk_live_YOUR_KEY" -H "X-Source-Id: conn_abc123" \
-H "Content-Type: application/json" \
-d '{"payload":"<IDOC><E1EDP01><VBELN>800001</VBELN><MATNR>MAT-100</MATNR></E1EDP01></IDOC>","format":"xml"}'
# 4. Print from ingested data
curl -X POST https://labelinn.com/v1/connect/sources/conn_abc123/print \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"printer_id":"prt_shipping_dock","design_id":"dsg_delivery_note","ingest_id":"ing_xyz789","copies":1}'
Dynamic Images & QR Codes
Create designs with dynamic image and QR code elements. Change product photos, logos, and QR codes per label β with full control over image fit mode.
async function printProductLabel(product) {
const response = await fetch('https://labelinn.com/v1/designs/dsg_product_shelf/print', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_id: 'prt_retail_store',
data: {
product_name: product.name,
price: product.price,
sku: product.sku,
product_image: product.image_url, // Dynamic image URL
qr_code: `https://yourstore.com/p/${product.slug}`, // QR content
},
element_overrides: {
product_image: { fit: 'contain' }, // Don't stretch
},
copies: 2,
}),
});
return response.json();
}
const products = [
{ name: 'Wireless Mouse', price: 'βΊ249.90', sku: 'ELEC-WM-01',
image_url: 'https://cdn.example.com/mouse.jpg', slug: 'wireless-mouse' },
{ name: 'USB-C Hub', price: 'βΊ179.90', sku: 'ELEC-HB-02',
image_url: 'https://cdn.example.com/hub.jpg', slug: 'usb-c-hub' },
];
for (const p of products) {
const result = await printProductLabel(p);
console.log(`${p.name}: ${result.data.id}`);
}
import requests
API_KEY = 'sk_live_YOUR_KEY'
def print_product_label(product):
return requests.post(
'https://labelinn.com/v1/designs/dsg_product_shelf/print',
headers={'Authorization': f'Bearer {API_KEY}'},
json={
'printer_id': 'prt_retail_store',
'data': {
'product_name': product['name'],
'price': product['price'],
'sku': product['sku'],
'product_image': product['image_url'],
'qr_code': f"https://yourstore.com/p/{product['slug']}",
},
'element_overrides': {'product_image': {'fit': 'contain'}},
'copies': 2,
},
).json()
products = [
{'name': 'Wireless Mouse', 'price': 'βΊ249.90', 'sku': 'ELEC-WM-01',
'image_url': 'https://cdn.example.com/mouse.jpg', 'slug': 'wireless-mouse'},
]
for p in products:
result = print_product_label(p)
print(f" {p['name']}: {result['data']['id']}")
curl -X POST https://labelinn.com/v1/designs/dsg_product_shelf/print \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"printer_id": "prt_retail_store",
"data": {
"product_name": "Wireless Mouse",
"price": "βΊ249.90",
"sku": "ELEC-WM-01",
"product_image": "https://cdn.example.com/mouse.jpg",
"qr_code": "https://yourstore.com/p/wireless-mouse"
},
"element_overrides": {
"product_image": { "fit": "contain" }
},
"copies": 2
}'
fill (default β stretches to fill), contain (fit inside, may letterbox), cover (fill and crop), none (original size), scaleDown (contain but never upscale). Works on image and PDF elements.
SDKs & Integration
Official SDK packages with full Data Connect support. Install for your language, or use LabelInn's REST API with any HTTP client.
Install
npm install labelinn
pip install labelinn
dotnet add package LabelInn
go get github.com/labelinn/labelinn-go
Quick Integration Examples
const response = await fetch('https://labelinn.com/v1/designs/DESIGN_ID/print', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
printer_id: 'printer_abc123',
data: {
product_name: 'Organic Coffee',
sku: 'COF-001',
weight: '250g',
},
copies: 1,
}),
});
const result = await response.json();
console.log('Job ID:', result.data.id);
console.log('Status:', result.data.status);
import requests
response = requests.post(
'https://labelinn.com/v1/designs/DESIGN_ID/print',
headers={'Authorization': 'Bearer sk_live_YOUR_KEY'},
json={
'printer_id': 'printer_abc123',
'data': {
'product_name': 'Organic Coffee',
'sku': 'COF-001',
'weight': '250g',
},
'copies': 1,
},
)
result = response.json()
print(f"Job ID: {result['data']['id']}")
print(f"Status: {result['data']['status']}")
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk_live_YOUR_KEY");
var payload = new {
printer_id = "printer_abc123",
data = new {
product_name = "Organic Coffee",
sku = "COF-001",
weight = "250g"
},
copies = 1
};
var response = await client.PostAsJsonAsync(
"https://labelinn.com/v1/designs/DESIGN_ID/print", payload);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine($"Job ID: {result.GetProperty("data").GetProperty("id")}");
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]interface{}{
"printer_id": "printer_abc123",
"data": map[string]string{
"product_name": "Organic Coffee",
"sku": "COF-001",
"weight": "250g",
},
"copies": 1,
})
req, _ := http.NewRequest("POST",
"https://labelinn.com/v1/designs/DESIGN_ID/print",
bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer sk_live_YOUR_KEY")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
data := result["data"].(map[string]interface{})
fmt.Println("Job ID:", data["id"])
}
Action: Webhooks by Zapier β Custom Request
URL: https://labelinn.com/v1/designs/YOUR_DESIGN_ID/print
Method: POST
Headers:
Authorization: Bearer sk_live_YOUR_KEY
Content-Type: application/json
Body (JSON):
{
"printer_id": "YOUR_PRINTER_ID",
"data": {
"customer_name": "{{trigger_customer_name}}",
"order_number": "{{trigger_order_id}}",
"address": "{{trigger_shipping_address}}"
}
}
// Trigger: When a new order comes in from Shopify/WooCommerce/etc.
POST /v1/designs/:id/print with your data.