DEVELOPER DOCUMENTATION

ZPL to PDF API.

One HTTP request turns ZPL into a multi-page PDF or PNG images. Send the ZPL as the request body; get the file back. No SDK, no account for small requests, and labels are never stored.

Quick start

curl -X POST "https://blznworks.com/api/zpl/render?width=4&height=6&dpi=203" \
  --data-binary @labels.zpl -H "Content-Type: text/plain" -o labels.pdf

That's it: each ^XA … ^XZ block in labels.zpl becomes one page of labels.pdf, at 4 × 6 inches. Without a key you are on the free plan (5 labels per request, 50 per day per IP address).

Endpoint

POST https://blznworks.com/api/zpl/render

Query parameters

NameDefaultValues
width, height4, 6Label size, decimal with a dot. 10–381 mm (0.4–15 in) per side.
unitinin or mm
dpi203203, 300 or 600. Or dpmm = 8, 12, 24. Use the density the ZPL was written for.
formatpdfpdf: one page per label. png: a PNG for one label, a zip of PNGs for several. json: base64 PNG previews of the first 12 labels, see below.

Body

Authentication

Optional. Send your Pro license key as Authorization: Bearer BLZN-XXXXX-… (or X-Api-Key). The same key works in the web tool. The API counts as one device of the license.

Responses

200 with the file (application/pdf, image/png or application/zip) and these headers:

HeaderMeaning
X-Label-CountLabels found and rendered
X-Planfree or pro
X-Labels-Remaining, X-Labels-Limit, X-Labels-ResetQuota left, the daily (free) or monthly (Pro) limit, and when it resets (UTC, ISO 8601)
X-Zpl-WarningsNumber of notes, e.g. printer-only commands such as ^PQ that were ignored. format=json lists them.

format=json returns { ok, labels, previewed, warnings, images, plan, remaining, limit, resetsAt }, where images are base64 PNGs of up to 12 labels, as the web tool's preview shows. Only previewed labels count toward the quota. Use it for previews; use pdf or png for output.

Errors

Errors are JSON: { "ok": false, "error": "too_many_labels", "message": "…" }.

StatuserrorWhat to do
400invalid_size, invalid_dpi, invalid_format, no_labels, size, empty, zip_invalidFix the request; message says what is wrong
401invalid_keyCheck the key, or leave it out to use the free plan
402too_many_labels, zip_requires_proThe request needs Pro, or more than the per-request limit: split it
403 / 409license_inactive / device_limitThe license ended, was refunded, or all its devices are in use
413too_largeBody over 512 KB (free) or 16 MB (Pro)
422render_failedA label could not be drawn; message names it
429quota_exceeded, or no bodyDaily/monthly quota used, or more than 20 requests a minute (120 with a key). Wait, then retry
503busy, timeoutRetry after Retry-After seconds; split very large batches

Examples

curl

# Free: one label, PNG at 300 dpi, 100 x 150 mm
curl -X POST "https://blznworks.com/api/zpl/render?width=100&height=150&unit=mm&dpi=300&format=png" \
  --data-binary "^XA^FO50,50^A0N,60,60^FDHello^FS^XZ" -o label.png

# Pro: a zip of many .zpl files to one PDF
curl -X POST "https://blznworks.com/api/zpl/render?width=4&height=6&dpi=203" \
  -H "Authorization: Bearer $BLZN_KEY" -H "Content-Type: application/zip" \
  --data-binary @labels.zip -o labels.pdf

C# (.NET 6+)

using System.Net.Http.Headers;

using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("BLZN_KEY"));

var zpl = await File.ReadAllTextAsync("labels.zpl");
using var response = await http.PostAsync(
    "https://blznworks.com/api/zpl/render?width=4&height=6&dpi=203&format=pdf",
    new StringContent(zpl, System.Text.Encoding.UTF8, "text/plain"));

if (!response.IsSuccessStatusCode)
    throw new Exception(await response.Content.ReadAsStringAsync()); // {"ok":false,"error":"…","message":"…"}

await File.WriteAllBytesAsync("labels.pdf", await response.Content.ReadAsByteArrayAsync());
Console.WriteLine($"Labels: {response.Headers.GetValues("X-Label-Count").First()}, left: {response.Headers.GetValues("X-Labels-Remaining").First()}");

JavaScript (Node 18+ or the browser)

import { readFile, writeFile } from "node:fs/promises";

const zpl = await readFile("labels.zpl", "utf8");
const response = await fetch("https://blznworks.com/api/zpl/render?width=4&height=6&dpi=203&format=pdf", {
  method: "POST",
  headers: { "Content-Type": "text/plain", Authorization: `Bearer ${process.env.BLZN_KEY}` },
  body: zpl,
});
if (!response.ok) throw new Error((await response.json()).message);
await writeFile("labels.pdf", Buffer.from(await response.arrayBuffer()));
console.log("labels:", response.headers.get("X-Label-Count"), "left:", response.headers.get("X-Labels-Remaining"));

The API sends Access-Control-Allow-Origin: * and reads no cookies, so it also works from a browser page. Never put a Pro key in public web pages: call the API from your server.

Plans and limits

Free (no key)Pro
Labels per request5500
Quota50 labels a day per IP20,000 labels a month per license
Body512 KB of ZPL16 MB, ZPL or zip (up to 64 MB unpacked)
Requests per minute20 per IP120 per IP
Price$0$12 / month or $120 / year

Get a Pro key

Current limits are also served as JSON at GET https://blznworks.com/api/zpl/limits.

Rendering notes

Questions or a command that renders wrongly? Contact support with a sample label.