ZPL rendering API: ZPL til PNG og PDF over HTTP
En endepunkt gjengir ZPL til PNG eller PDF. Det er kompatibelt med Labelarys v1 API: samme stier, overskrifter og feil.
Rendre en etikett
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 | Skrive tetthet: 6dpmm, 8dpmm, 12dpmm, 24dpmm. |
width, height | Etikettstørrelse i tommer, for eksempel 4x6 eller 2.25x1.25. Opptil 15 tommer hver. |
index | Hvilken etikett som skal gjengis, starter på 0. La det være ute med PDF-utdata for å få hver etikett, en per side. |
zpl | For GET, den URL-kodede ZPL. Kode # som %23. Bruk POST for alt som er langt. |
Med POST, send ZPL som det rå forespørselstopp, eller som et multipart skjema felt kalt file.
API-nøkler
Uten en nøkkel får du 3 etiketter per dag per IP-adresse, nok til å prøve det. Med en nøkkel fra dashbordet ditt, send det i X-API-Key-overskriften og grensene for ditt arbeidsområdes plan gjelder.
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 av dem sender label.zpl, lagrer label.pdf og viser API-ens feilmelding hvis noe er galt. For en PNG, be om image/png og legg til 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"
Forespørsel overskrifter
| Overskrift | Verdier | 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 klokken | 0 |
X-Language | zpl, epl, tspl, auto: kroppens skriver språk. Uten det blir en kropp uten ^ eller ~ lest som EPL eller TSPL når det ser ut som en. | zpl |
X-API-Key | Din arbeidsområdenøkkel, valgfri | — |
Begrensninger
- 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 feil
Vellykkede svar bærer X-Total-Count, antall etiketter ZPL produserer, ^PQ kopier inkludert. Feil er ren tekst som begynner med ERROR:.
| Status | Betydning |
|---|---|
| 400 | Et parameter er ugyldig, etiketten er for stor, eller indeksen er utenfor området. |
| 401 | API-nøkkelen er ukjent eller ble tilbakekalt. |
| 406 | Accept headeren ber om et utdataformat som ikke er tilgjengelig ennå. |
| 413 | Kroppen er over 1 MB, eller ZPL-en produserer mer enn 50 etiketter. |
| 429 | For mange forespørsel eller etiketter for planen din. Vent antall sekunder i Retry-After. |
| 503 | Etiketten tok mer enn 10 sekunder å gjengi, eller tjenesten er på kapasitet. Prøv igjen, eller senk tettheten eller størrelsen. |
Hva motoren tegner, ignorerer eller ikke støtter ennå er på the compatibility page; hvor raskt den gjengir, målt på produksjonsserveren, på the benchmarks page.
Malene: fyll en lagret design med dataene dine
Design en etikett med {{variables}} plassholdere, lagre den, og kopier ID-en fra dashbordet ditt: d123 for et design, l45 for en lagret etikett. Deretter sender systemet ditt bare dataene, med en API-nøkkel.
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
Bruk {"data": {...}} for én etikett eller {"rows": [...]} for opptil 50. Accept gir en PDF eller PNG, eller text/plain den utfylte ZPL-en som sendes til skriveren. Verdiene er escaperte, så dataene dine kan aldri starte en ZPL-kommando.
Skriv ut på en lokal skriver
Med print agent kjørende ved siden av skriveren, setter POST /v1/print-jobs ZPL i kø for den og POST /v1/templates/{id}/print fyller ut et lagret design. Begge tar et printer-navn og returnerer et job ID; GET /v1/print-jobs/{id} forteller deg om det ble skrevet ut.
Spørsmål
Hvor mye koster API-et?
Uten en nøkkel kan du prøve det med 3 etiketter per dag. En gratis nøkkel tillater 20 etiketter per dag, og paid plans starter på $29 i måneden for 100 000 etiketter.
Er det kompatibelt med Labelary?
Ja: de samme stiene, overskriftene og feilene. Endre vertsnavnet og send nøkkelen din, som migration guide viser.
Lagrer dere etikettene mine?
Ikke med en API-nøkkel: etiketten blir gjengitt og returnert. privacy page har detaljene og fristene.
Kan en AI-assistent bruke det?
Ja, gjennom MCP server: Claude, Cursor og andre assistenter kan generere etiketter med det.
OpenAPI og Markdown
Den samme kontrakten er publisert som OpenAPI 3.1 og som Markdown, for kodegeneratorer og kodeassistenter.
Trinn-for-trinn veiledninger: Python, Node.js, PHP, C#. Flytte fra Labelary: migration guide.