Migrate from Labelary
Side-by-side examples
Labelary calls next to their zpl.tools equivalents, for the three most common requests
Each example below shows the Labelary call and the zpl.tools call for
the same request, in curl, Python, and Node. The only changes are the
base URL and the added X-API-Key header — everything else (path
shape, Accept negotiation, request body) is unchanged.
1. Single label → PNG
The default case: one ^XA...^XZ label, rendered to 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.pngPython
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
Same request, 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.pdfPython
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
Several ^XA...^XZ pairs in one submission, rendered as a multi-page
PDF (omit the {index} path segment). This is the batch case — one
request instead of N.
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.pdfPython
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
| Labelary | zpl.tools | Notes |
|---|---|---|
GET /v1/printers/{dpmm}/labels/{w}x{h}/{index}/{zpl} | GET /compatibility/labelary/v1/printers/{dpmm}/labels/{w}x{h}/{index}/{zpl} | Avoid for large ZPL — our URL-length cap (16 KB) is friendlier than Labelary's (~3 KB), but POST is still the better default. |
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; PNG here returns 404 (an index is required for PNG). |
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.