API de renderitzat ZPL: ZPL a PNG i PDF a través d'HTTP
Un punt final renderitza ZPL a PNG o PDF. És compatible amb l'API v1 de Labelary: mateixes rutes, encapçalaments i errors.
Renderitza una etiqueta
GET https://api.openzpl.com/v1/printers/{dpmm}/labels/{width}x{height}/{index}/{zpl}
POST https://api.openzpl.com/v1/printers/{dpmm}/labels/{width}x{height}/{index}
POST https://api.openzpl.com/v1/printers/{dpmm}/labels/{width}x{height}/
dpmm | Densitat d'impressió: 6dpmm, 8dpmm, 12dpmm, 24dpmm. |
width, height | Mida etiqueta en polzades, per exemple 4x6 o 2.25x1.25. Fins a 15 polzades cadascun. |
index | Quina etiqueta renderitzar, començant des de 0. Deixa-ho sense especificar amb sortida PDF per obtenir cada etiqueta, una per pàgina. |
zpl | Per GET, el ZPL codificat en URL. Codifiqueu # com %23. Utilitzeu POST per a qualsevol cosa llarga. |
Amb POST, envia el ZPL com el cos de la sol·licitud en brut, o com un camp de formulari multipart anomenat file.
Claus de l'API
Sense una clau, obteniu 3 etiquetes al dia per adreça IP, suficient per provar-ho. Amb una clau del vostre tauler de control, envieu-la en el capçalera X-API-Key i s'apliquen els límits del pla del vostre espai de treball.
curl https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/0/ \ -H "X-API-Key: oz_live_…" --data-binary @label.zpl > label.png
Exemples
Cada un envia label.zpl, guarda label.pdf i mostra el missatge d'error de l'API si alguna cosa va malament. Per un PNG, demaneu image/png i afegiu l'índex de l'etiqueta (/0/) a la URL.
curl https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/ \
-H "Accept: application/pdf" \
--data-binary @label.zpl --fail-with-body -o label.pdf
import requests # pip install requests
with open("label.zpl", "rb") as f:
res = requests.post(
"https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/",
data=f.read(),
headers={"Accept": "application/pdf"},
timeout=30,
)
if not res.ok:
raise SystemExit(res.text)
with open("label.pdf", "wb") as f:
f.write(res.content)
// Node.js 18+; save as label.mjs
import { readFile, writeFile } from "node:fs/promises";
const res = await fetch("https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/", {
method: "POST",
headers: { Accept: "application/pdf" },
body: await readFile("label.zpl"),
});
if (!res.ok) throw new Error(await res.text());
await writeFile("label.pdf", Buffer.from(await res.arrayBuffer()));
<?php
$ch = curl_init("https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => file_get_contents("label.zpl"),
CURLOPT_HTTPHEADER => ["Accept: application/pdf"],
CURLOPT_RETURNTRANSFER => true,
]);
$pdf = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) !== 200) {
exit($pdf);
}
file_put_contents("label.pdf", $pdf);
using var http = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post,
"https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/")
{
Content = new StringContent(File.ReadAllText("label.zpl")),
};
req.Headers.Add("Accept", "application/pdf");
var res = await http.SendAsync(req);
if (!res.IsSuccessStatusCode)
throw new Exception(await res.Content.ReadAsStringAsync());
File.WriteAllBytes("label.pdf", await res.Content.ReadAsByteArrayAsync());
// Java 11+
import java.net.URI;
import java.net.http.*;
import java.nio.file.Path;
public class Label {
public static void main(String[] args) throws Exception {
var req = HttpRequest.newBuilder(
URI.create("https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/"))
.header("Accept", "application/pdf")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("label.zpl")))
.build();
var res = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofByteArray());
if (res.statusCode() != 200)
throw new RuntimeException(new String(res.body()));
java.nio.file.Files.write(Path.of("label.pdf"), res.body());
}
}
package main
import (
"io"
"log"
"net/http"
"os"
)
func main() {
zpl, err := os.Open("label.zpl")
if err != nil {
log.Fatal(err)
}
req, _ := http.NewRequest("POST", "https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/", zpl)
req.Header.Set("Accept", "application/pdf")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
if res.StatusCode != 200 {
log.Fatal(string(body))
}
os.WriteFile("label.pdf", body, 0o644)
}
require "net/http"
uri = URI("https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/")
res = Net::HTTP.post(uri, File.binread("label.zpl"), "Accept" => "application/pdf")
abort res.body unless res.is_a?(Net::HTTPSuccess)
File.binwrite("label.pdf", res.body)
Invoke-WebRequest -Method Post `
-Uri "https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/" `
-Headers @{ Accept = "application/pdf" } `
-InFile "label.zpl" -OutFile "label.pdf"
Capçaleres de la sol·licitud
| Capçalera | Valors | Per defecte |
|---|---|---|
Accept | image/png, application/pdf | PNG |
X-Quality | Grayscale (8-bits, vores suaus) o Bitonal (1-bit, fitxers més petits) | Grayscale |
X-Rotation | 0, 90, 180, 270, en el sentit de les agulles del rellotge | 0 |
X-Language | zpl, epl, tspl, auto: el llenguatge de la impressora del cos. Sense això, un cos sense ^ o ~ es llegeix com a EPL o TSPL quan s'assembla a un. | zpl |
X-API-Key | La teva clau d'espai de treball, opcional | — |
Límits
- Without a key: 3 requests per second and 3 labels per UTC day, per IP address. With a free key from the dashboard: 20 labels per UTC day.
- Labels, not requests, count against the allowance (per UTC day on Free, per UTC calendar month on paid plans): every label rendered,
^PQcopies and PDF pages included. A 10-label PDF is 1 request and 10 labels. - Every request: up to 50 labels, a 1 MB body, 15 inches per side, and 10 seconds of render time.
- Paid plans (Pro $29/month: 10 requests/s and 100,000 labels/month, Business $99/month: 20 requests/s and 1,000,000 labels/month): subscriptions, monthly or yearly, from the dashboard's Billing page (card, through Stripe), and you can cancel at any time. The workspace's API keys move to the plan's limits as soon as the payment is approved.
- Over a limit the API answers
429withRetry-After(seconds) and a body that names the limit, e.g.ERROR: Daily limit reached: 20 labels per UTC day on this plan (^PQ copies and PDF pages count).
Respostes i errors
Les respostes aconseguides porten X-Total-Count, el nombre d'etiquetes que produeix el ZPL, amb ^PQ còpies incloses. Els errors són text simple que comença amb ERROR:.
| Estat | Significat |
|---|---|
| 400 | Un paràmetre és invàlid, l'etiqueta és massa gran, o l'índex està fora de rang. |
| 401 | La clau de l'API és desconeguda o ha estat revocada. |
| 406 | La capçalera Accept sol·licita un format de sortida que encara no està disponible. |
| 413 | El cos supera 1 MB, o el ZPL produeix més de 50 etiquetes. |
| 429 | Masses sol·licituds o etiquetes per al teu pla. Espera el nombre de segons indicat a Retry-After. |
| 503 | L'etiqueta ha tardat més de 10 segons a renderitzar, o el servei està a capacitat. Torna a intentar-ho, o redueix la densitat o la mida. |
El que dibuixa, ignora o encara no suporta el motor està en the compatibility page; quina velocitat té de renderitzar, mesurada al servidor de producció, en the benchmarks page.
Plantilles: ompliu un disseny desat amb les vostres dades
Dissenyeu una etiqueta amb marcadors de {{variables}}, deseu-la, i copieu el seu ID del vostre tauler: d123 per a un disseny, l45 per a una etiqueta desada. Després el vostre sistema envia només les dades, amb una clau API.
curl https://api.openzpl.com/v1/templates/d123 \
-H "X-API-Key: oz_live_…" -H "Accept: application/pdf" \
-d '{"rows": [{"sku": "A-100"}, {"sku": "A-101"}]}' > labels.pdf
Utilitzeu {"data": {...}} per a una etiqueta o {"rows": [...]} per a un màxim de 50. Accept proporciona un PDF o PNG, o text/plain el ZPL omplert per enviar a una impressora. Els valors estan escapats, així que les vostres dades mai poden començar un comandament ZPL.
Imprimiu en una impressora local
Amb el print agent funcionant al costat de la impressora, POST /v1/print-jobs posa en espera ZPL per a ella i POST /v1/templates/{id}/print omple un disseny desat. Ambdues requereixen un nom de printer i retornen un ID de feina; GET /v1/print-jobs/{id} et diu si s'ha imprès.
Preguntes
Quant costa l'API?
Sense una clau pots provar-ho amb 3 etiquetes al dia. Una clau gratuïta permet 20 etiquetes al dia, i paid plans comencen a $29 al mes per 100,000 etiquetes.
És compatible amb Labelary?
Sí: els mateixos camins, capçaleres i errors. Canvieu el nom d'àncora i envieu la vostra clau, tal com mostra el migration guide.
Feu servir les meves etiquetes?
No amb una clau API: l'etiqueta es renderitza i s'envia de nou. La privacy page té els detalls i els terminis.
Pot un assistent d'IA utilitzar-ho?
Sí, a través del MCP server: Claude, Cursor i altres assistents poden generar etiquetes amb això.
OpenAPI i Markdown
El mateix contracte es publica com OpenAPI 3.1 i com Markdown, per a generadors de codi i assistents de codificació.
Guies pas a pas: Python, Node.js, PHP, C#. Migrant des de Labelary: migration guide.