← Back to Blog
Developers & API

Label API Quickstart: Generate ZPL Labels via REST API

Benjamin HayesOctober 10, 2026648 views

A label API is a REST endpoint that accepts label data and returns print-ready output, such as a ZPL string, without any manual design work. Label Toolkit's free /api/v1/zpl endpoint does exactly that: send a JSON payload describing your label content, get back valid ZPL II code that any Zebra-compatible printer can consume, all from your own application with no browser required.

  • Label Toolkit's label API is free to start, requires no installation, and returns ZPL II strings suitable for direct spool to Zebra, Honeywell, and SATO printers.
  • A minimal request needs only a label template ID and a data object; barcode generation, font scaling, and quiet-zone padding are handled server-side.
  • The API accepts Content-Type: application/json and responds in under 200 ms for single-label requests under normal load.
  • You can test every response in the browser using the Label Toolkit online ZPL preview designer before wiring up production code.

Who should use a label generation API?

If your team prints more than a few dozen labels a day, or if label data lives inside an order management system, a WMS, or an e-commerce platform, a label API removes the copy-paste step entirely. Engineers at 3PLs, e-commerce brands, and manufacturing operations use Label Toolkit's endpoint to generate shipping labels, warehouse bin labels, product compliance labels, and serialized asset tags on demand, without touching a design tool after the initial template setup.

ZPL II: a quick primer

ZPL II (Zebra Programming Language II) is the page-description language Zebra Technologies introduced for its thermal printers. A ZPL label is a plain-text string that starts with ^XA (start of label) and ends with ^XZ (end of label). Every element, a text field, a barcode, an image, sits between those delimiters and is addressed by dot-row and dot-column coordinates relative to the printhead. Label Toolkit's API compiles your JSON data into this string so you never have to write raw ZPL by hand, though our complete ZPL II guide is there if you want to understand every command the API emits.

diagram showing JSON payload going into Label Toolkit API and ZPL string coming out, with an arrow pointing to a Zebra printer

Prerequisites

  1. Create a free Label Toolkit account at /register. Your API key is generated automatically on signup.
  2. Design or choose a label template in the Label Toolkit designer. Note the template ID shown in the URL or the template settings panel.
  3. Identify the variable fields in your template. Each field name in the designer maps directly to a key in the API's data object.
  4. Have a Zebra-compatible printer available, or use the Label Toolkit ZPL preview tool to verify output without a physical printer.

API authentication

Every request must include your API key in the Authorization header as a Bearer token:

Authorization: Bearer YOUR_API_KEY

Keep your API key out of client-side code. Store it as an environment variable and inject it at runtime. Label Toolkit uses HTTPS-only endpoints, so the token is encrypted in transit.

Endpoint reference

PropertyValue
MethodPOST
URLhttps://labeltoolkit.com/api/v1/zpl
Content-Typeapplication/json
Acceptapplication/json
Response body keyzpl (string)
Typical latencyUnder 200 ms for a single label
Rate limit (free tier)60 requests per minute

Request body structure

The JSON body takes three top-level keys:

{
  "templateId": "tpl_abc123",
  "labelSize": {
    "width": 101.6,
    "height": 152.4,
    "unit": "mm"
  },
  "data": {
    "recipientName": "Acme Corp",
    "trackingNumber": "1Z9999999999999999",
    "sku": "SKU-00421"
  }
}

templateId references the label template. labelSize is optional if the template already has fixed dimensions; include it to override at request time. data is a flat key-value map where each key matches a variable field name in the template.

Step-by-step: your first API call

  1. Copy your API key from the Label Toolkit account dashboard.
  2. Open a terminal and run the curl command below, substituting your real key and template ID.
  3. Inspect the zpl field in the response. It should begin with ^XA and end with ^XZ.
  4. Paste that ZPL string into the Label Toolkit ZPL preview or send it directly to your printer's TCP/IP socket on port 9100.
  5. If the output looks correct, wrap the call in your application code using the language examples below.

Code examples

curl

curl -X POST https://labeltoolkit.com/api/v1/zpl \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": "tpl_abc123",
    "data": {
      "recipientName": "Acme Corp",
      "trackingNumber": "1Z9999999999999999"
    }
  }'

Node.js (fetch)

const response = await fetch('https://labeltoolkit.com/api/v1/zpl', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.LABEL_TOOLKIT_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    templateId: 'tpl_abc123',
    data: {
      recipientName: 'Acme Corp',
      trackingNumber: '1Z9999999999999999'
    }
  })
});

const { zpl } = await response.json();
console.log(zpl); // ^XA ... ^XZ

Python (requests)

import os
import requests

resp = requests.post(
    'https://labeltoolkit.com/api/v1/zpl',
    headers={
        'Authorization': f'Bearer {os.environ["LABEL_TOOLKIT_KEY"]}',
        'Content-Type': 'application/json'
    },
    json={
        'templateId': 'tpl_abc123',
        'data': {
            'recipientName': 'Acme Corp',
            'trackingNumber': '1Z9999999999999999'
        }
    }
)

zpl = resp.json()['zpl']
print(zpl)  # ^XA ... ^XZ

PHP (Guzzle)

use GuzzleHttp\Client;

$client = new Client();
$response = $client->post('https://labeltoolkit.com/api/v1/zpl', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('LABEL_TOOLKIT_KEY'),
        'Content-Type'  => 'application/json'
    ],
    'json' => [
        'templateId' => 'tpl_abc123',
        'data' => [
            'recipientName'   => 'Acme Corp',
            'trackingNumber'  => '1Z9999999999999999'
        ]
    ]
]);

$zpl = json_decode($response->getBody(), true)['zpl'];
echo $zpl; // ^XA ... ^XZ

Understanding the ZPL output

The API returns ZPL II. A typical single-field label with a Code 128 barcode looks like this (abbreviated for readability):

^XA
^FO20,20^A0N,30,30^FDAcme Corp^FS
^FO20,70^BCN,80,Y,N,N^FD1Z9999999999999999^FS
^XZ

Breaking that down: ^FO20,20 sets the field origin at 20 dots from the left edge and 20 dots from the top. At 203 dpi (dots per inch), 20 dots is roughly 2.5 mm. ^A0N,30,30 selects scalable font 0 at 30 x 30 dots. ^FD opens the field data and ^FS closes it. ^BCN,80,Y,N,N renders a Code 128 barcode (the ^BC command) at 80 dots tall with a human-readable interpretation line. If your printer runs at 300 dpi, the same coordinate values produce a proportionally smaller physical element, so you may want to scale coordinates by 1.48 (300 / 203) or use the labelSize override to let the API do it for you.

For a deep dive into every command the API may emit, the ZPL commands reference hub covers ^XA, ^FO, ^FD, ^BC, ^BQ, ^A, and more with syntax tables and live examples.

Sending ZPL to a Zebra printer

Once you have the ZPL string, print it by opening a raw TCP socket to the printer's IP address on port 9100 and writing the string as UTF-8 bytes. No printer driver is needed. This is the same raw-socket method Zebra's own ZebraLink and Print DNA toolkits use. The Zebra ZPL Programming Guide (available from Zebra's support portal) documents the full command set if you need to inspect or modify the raw output. For Windows environments, you can also print to a shared printer using the GDI raw-mode spooler, but the TCP socket approach is language-agnostic and far simpler.

Bulk label generation

To generate many labels in one pass, call the endpoint in a loop and collect the ZPL strings, then concatenate them. ZPL supports multi-label files: each label's ^XA ... ^XZ block is self-contained, so you can append them into a single string and send that to the printer. The printer processes them sequentially. A 500-label batch at the free tier uses about 8-9 minutes of rate-limit budget; upgrade tiers lift the cap for high-volume production runs.

If your data lives in a spreadsheet, consider Label Toolkit's built-in data-merge workflow as a complement to the API. The auto-numbering and conditional fields guide shows how to generate serialized labels with incrementing values, which the API also supports by passing a sequence field in the data object.

Error handling and status codes

HTTP statusMeaningCommon cause
200SuccessZPL string returned in zpl field
400Bad requestMissing templateId, malformed JSON, or unknown field key
401UnauthorizedMissing or invalid API key
404Not foundTemplate ID does not exist or belongs to a different account
429Too many requestsRate limit exceeded; back off and retry after 60 seconds
500Server errorTemporary issue; retry with exponential backoff

Always check response.ok (or the HTTP status code) before using the zpl field. A 400 response body includes an error string describing which field failed validation, which makes debugging straightforward in CI pipelines.

Barcode types supported by the API

The API generates barcodes by reading the field type set in the template designer. Supported symbologies include Code 128, QR Code, Data Matrix, EAN-13, UPC-A, GS1-128, ITF-14, and Code 39. The GS1 barcode standards define the data structure rules for GS1-128 and ITF-14; Label Toolkit validates the Application Identifier prefix automatically when those symbologies are selected. Quiet zones (the mandatory white space around a barcode that scanners need to detect the start and stop patterns) are included in the rendered ZPL coordinates, so you do not need to calculate them manually.

Comparing the API to building ZPL from scratch

FactorLabel Toolkit APIHand-crafted ZPL strings
Setup timeMinutes (design template, call endpoint)Days to weeks (learn ZPL syntax, test on hardware)
DPI awarenessHandled server-side per printer configManual coordinate scaling per printer model
Barcode validationBuilt-in check digit and quiet-zone calculationMust implement or use a separate library
Template changesEdit in designer, API output updates instantlyRequires code changes and redeployment
Multi-language supportSame REST endpoint regardless of languageNeed ZPL library for each language stack
CostFree tier availableEngineering time only
side-by-side screenshot of the Label Toolkit template designer on the left and a terminal showing a curl response with a ZPL string on the right

Tips for production integrations

  • Cache the ZPL output when the same data will print multiple copies; the label content is deterministic for identical inputs.
  • Use a staging template ID in your CI/CD pipeline and swap to the production template ID in your deployment environment variable.
  • Log the raw ZPL string on 400 errors so you can paste it into the Label Toolkit ZPL preview tool for immediate visual diagnosis.
  • For 300 dpi printers, set "dpi": 300 inside the labelSize object; the API scales dot coordinates accordingly rather than leaving you to multiply every ^FO coordinate by hand.
  • If your printer firmware is older and expects EPL2 instead of ZPL, see the ZPL vs EPL comparison before integrating; the two languages are not compatible.

Frequently asked questions

Is the Label Toolkit label API really free?

Yes. The free tier allows up to 60 requests per minute with no monthly label cap during normal use. Paid tiers raise rate limits and add priority support for high-volume production environments.

What printers work with the ZPL output from the API?

Any printer that understands ZPL II works, including the full Zebra ZD and ZT series, Honeywell PC and PX series, SATO printers in ZPL-emulation mode, and many others. Send the string to TCP port 9100 on the printer's IP address using a raw socket connection.

Can I generate labels with barcodes and images, not just text?

Yes. If your template contains a barcode field (Code 128, QR, GS1-128, and so on) or a logo image, the API encodes them correctly in the ZPL output. The barcode data comes from the data object key that matches the field; the logo is stored in the template and embedded via the ^GF command automatically.

How do I handle variable-length fields, such as addresses that might be one or two lines?

Set up conditional fields in your template using Label Toolkit's conditional field feature. Pass the optional value in the data object; if the key is absent, the field renders as empty. The conditional fields guide covers the exact syntax.

Where can I read the full API documentation?

The complete endpoint reference, including all request parameters, response schemas, and error codes, lives in the Label Toolkit developer documentation.

Ready to generate your first label programmatically? Create a free Label Toolkit account and have a working API call running in under five minutes.

#label api #generate zpl via api #label generation rest api #automate label printing #bulk label api #node label api #python barcode label #php label generation
BH
Written by Benjamin Hayes
View profile →