ZPL rendering API: ZPL til PNG og PDF over HTTP
Én slutpunkt gengiver ZPL til PNG eller PDF. Det er kompatibelt med Labelary's v1 API: samme stier, overskrifter og fejl.
Generér en label
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 | Printtæthed: 6dpmm, 8dpmm, 12dpmm, 24dpmm. |
width, height | Etiket størrelse i tommer, for eksempel 4x6 eller 2.25x1.25. Op til 15 tommer hver. |
index | Hvilken etiket der skal renderes, startende ved 0. Lad den være ude med PDF output for at få hver etiket, én pr. side. |
zpl | For GET, den URL-kodede ZPL. Kod # som %23. Brug POST til alt langt. |
Med POST, send ZPL som den rå anmodningskrop, eller som et multipart formularfelt med navnet file.
API nøgler
Uden en nøgle får du 3 etiketter om dagen pr. IP-adresse, nok til at prøve det. Med en nøgle fra dit dashboard, send det i X-API-Key header, og grænserne for din arbejdsplads plan gælder.
curl https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/0/ \ -H "X-API-Key: oz_live_…" --data-binary @label.zpl > label.png
Eksempler
Hver enkelt sender label.zpl, gemmer label.pdf og viser API'ens fejlsmelding, hvis noget er galt. For en PNG, spørg om image/png og tilføj etikettens indeks (/0/) til URL'en.
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"
Anmodningsheaders
| Overskrift | Værdier | Standard |
|---|---|---|
Accept | image/png, application/pdf | PNG |
X-Quality | Grayscale (8-bit, glatte kanter) eller Bitonal (1-bit, mindre filer) | Grayscale |
X-Rotation | 0, 90, 180, 270, med uret | 0 |
X-Language | zpl, epl, tspl, auto: kroppens printer sprog. Uden det bliver en krop uden ^ eller ~ læst som EPL eller TSPL, når den ligner en. | zpl |
X-API-Key | Dit arbejdsområde nøgle, valgfrit | — |
Grænser
- 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).
Svar og fejl
Succesfulde svar indeholder X-Total-Count, antallet af etiketter som ZPL producerer, ^PQ kopier inkluderet. Fejl er almindelig tekst, der starter med ERROR:.
| Status | Betydning |
|---|---|
| 400 | En parameter er ugyldig, etiketten er for stor, eller indekset er uden for rækkevidde. |
| 401 | API-nøglen er ukendt eller blev tilbagekaldt. |
| 406 | Accept headeren anmoder om et outputformat, som endnu ikke er tilgængeligt. |
| 413 | Kroppen er over 1 MB, eller ZPL producerer mere end 50 labels. |
| 429 | For mange anmodninger eller labels til din plan. Vent antallet af sekunder i Retry-After. |
| 503 | Labelen tog længere end 10 sekunder at gengive, eller tjenesten er ved at være fyldt. Prøv igen, eller sænk densiteten eller størrelsen. |
Hvad motoren tegner, ignorerer eller endnu ikke understøtter, er på the compatibility page; hvor hurtigt det gengiver, målt på produktionsserveren, på the benchmarks page.
Skabeloner: udfyld et gemt design med dine data
Design en etiket med {{variables}} pladsholdere, gem den, og kopier dens ID fra dit dashboard: d123 for et design, l45 for en gemt etiket. Så sender dit system kun dataene med en API-nøgle.
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
Brug {"data": {...}} til én label eller {"rows": [...]} til op til 50. Accept giver en PDF eller PNG, eller text/plain den udfyldte ZPL til at sende til en printer. Værdier er undsluppet, så dine data kan aldrig starte en ZPL-kommando.
Print på en lokal printer
Med print agent der kører ved siden af printeren, køer POST /v1/print-jobs ZPL til den, og POST /v1/templates/{id}/print udfylder et gemt design. Begge tager et printer navn og returnerer et job-ID; GET /v1/print-jobs/{id} fortæller dig, om det blev printet.
Spørgsmål
Hvor meget koster API'en?
Uden en nøgle kan du prøve det med 3 labels om dagen. En gratis nøgle tillader 20 labels om dagen, og paid plans starter ved $29 om måneden for 100.000 labels.
Er det kompatibelt med Labelary?
Ja: de samme stier, headers og fejl. Skift værtsnavnet og send din nøgle, som migration guide viser.
Opbevarer I mine labels?
Ikke med en API-nøgle: etiketten bliver gengivet og returneret. privacy page har detaljerne og fristerne.
Kan en AI-assistent bruge det?
Ja, via MCP server: Claude, Cursor og andre hjælpere kan generere mærkater med det.
OpenAPI og Markdown
Den samme kontrakt er offentliggjort som OpenAPI 3.1 og som Markdown, til kodegeneratorer og kodeassistenter.
Trin-for-trin vejledninger: Python, Node.js, PHP, C#. Flytning fra Labelary: migration guide.