zpl.tools
Migrate from Labelary

Side-by-side examples

Labelary calls next to their zpl.tools equivalents, for the three most common requests

Only the base URL and the added X-API-Key header change. The path shape, the Accept negotiation, and the request body do not change.

1. Single label → PNG

curl

# Labelary
curl -X POST "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/" \
  --data "^XA^FO50,50^FDHello World^FS^XZ" \
  -o label.png

# zpl.tools
curl -X POST "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0" \
  -H "X-API-Key: your_api_key_here" \
  --data "^XA^FO50,50^FDHello World^FS^XZ" \
  -o label.png

Python

import requests

zpl = "^XA^FO50,50^FDHello World^FS^XZ"

# Labelary
response = requests.post(
    "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/",
    data=zpl,
)

# zpl.tools
response = requests.post(
    "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0",
    headers={"X-API-Key": "your_api_key_here"},
    data=zpl,
)

with open("label.png", "wb") as f:
    f.write(response.content)

Node

const zpl = "^XA^FO50,50^FDHello World^FS^XZ";

// Labelary
let response = await fetch(
  "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/",
  { method: "POST", body: zpl }
);

// zpl.tools
response = await fetch(
  "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0",
  {
    method: "POST",
    headers: { "X-API-Key": "your_api_key_here" },
    body: zpl,
  }
);

const buffer = Buffer.from(await response.arrayBuffer());

2. Single label → PDF

The same request, with Accept: application/pdf instead of the default PNG.

curl

# Labelary
curl -X POST "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/" \
  -H "Accept: application/pdf" \
  --data "^XA^FO50,50^FDHello World^FS^XZ" \
  -o label.pdf

# zpl.tools
curl -X POST "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0" \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/pdf" \
  --data "^XA^FO50,50^FDHello World^FS^XZ" \
  -o label.pdf

Python

import requests

zpl = "^XA^FO50,50^FDHello World^FS^XZ"

# zpl.tools (Labelary call is identical minus the base URL / API key)
response = requests.post(
    "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0",
    headers={
        "X-API-Key": "your_api_key_here",
        "Accept": "application/pdf",
    },
    data=zpl,
)

with open("label.pdf", "wb") as f:
    f.write(response.content)

Node

const zpl = "^XA^FO50,50^FDHello World^FS^XZ";

// zpl.tools (Labelary call is identical minus the base URL / API key)
const response = await fetch(
  "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6/0",
  {
    method: "POST",
    headers: {
      "X-API-Key": "your_api_key_here",
      "Accept": "application/pdf",
    },
    body: zpl,
  }
);

const buffer = Buffer.from(await response.arrayBuffer());

3. Multi-label ZPL → all-labels PDF

Omit the {index} path segment. Several ^XA...^XZ pairs in one submission render as one multi-page PDF.

curl

zpl='^XA^FO50,50^FDLabel 1^FS^XZ^XA^FO50,50^FDLabel 2^FS^XZ^XA^FO50,50^FDLabel 3^FS^XZ'

# Labelary
curl -X POST "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/" \
  -H "Accept: application/pdf" \
  --data "$zpl" \
  -o labels.pdf

# zpl.tools
curl -X POST "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6" \
  -H "X-API-Key: your_api_key_here" \
  -H "Accept: application/pdf" \
  --data "$zpl" \
  -o labels.pdf

Python

import requests

zpl = (
    "^XA^FO50,50^FDLabel 1^FS^XZ"
    "^XA^FO50,50^FDLabel 2^FS^XZ"
    "^XA^FO50,50^FDLabel 3^FS^XZ"
)

# zpl.tools — no page-count cap; Labelary caps at 50 labels per request
response = requests.post(
    "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6",
    headers={
        "X-API-Key": "your_api_key_here",
        "Accept": "application/pdf",
    },
    data=zpl,
)

print(response.headers["X-Total-Count"])  # "3"
with open("labels.pdf", "wb") as f:
    f.write(response.content)

Node

const zpl =
  "^XA^FO50,50^FDLabel 1^FS^XZ" +
  "^XA^FO50,50^FDLabel 2^FS^XZ" +
  "^XA^FO50,50^FDLabel 3^FS^XZ";

const response = await fetch(
  "https://api.zpl.tools/compatibility/labelary/v1/printers/8dpmm/labels/4x6",
  {
    method: "POST",
    headers: {
      "X-API-Key": "your_api_key_here",
      "Accept": "application/pdf",
    },
    body: zpl,
  }
);

console.log(response.headers.get("X-Total-Count")); // "3"
const buffer = Buffer.from(await response.arrayBuffer());

Endpoint map

Labelaryzpl.toolsNotes
GET /v1/printers/{dpmm}/labels/{w}x{h}/{index}/{zpl}GET /compatibility/labelary/v1/printers/{dpmm}/labels/{w}x{h}/{index}/{zpl}Do not use this endpoint for large ZPL. The URL-length limit is 16 KB; the Labelary limit is approximately 3 KB. Use POST instead.
POST /v1/printers/{dpmm}/labels/{w}x{h}/{index}POST /compatibility/labelary/v1/printers/{dpmm}/labels/{w}x{h}/{index}Form-urlencoded or multipart file/zpl field, same as Labelary.
POST /v1/printers/{dpmm}/labels/{w}x{h}POST /compatibility/labelary/v1/printers/{dpmm}/labels/{w}x{h}All-labels endpoint, PDF only. A PNG request returns 404, because PNG requires an index.
POST /v1/graphics (image → ZPL/EPL/IPL/DPL/SBPL/PCL)Not implemented.
POST /v1/fonts (TTF → ZPL font)Not implemented.

See the full API reference for path parameters and every supported header.