ZPL рендеринг API: ZPL в PNG и PDF през HTTP
Един крайна точка рендерира ZPL в PNG или PDF. Тя е съвместима с v1 API на Labelary: същите пътища, заглавия и грешки.
Рендерирайте етикет
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 | Плътност на печата: 6dpmm, 8dpmm, 12dpmm, 24dpmm. |
width, height | Размер на етикет в инчове, например 4x6 или 2.25x1.25. До 15 инча всеки. |
index | Кой етикет да се обработи, започвайки от 0. Оставете го, ако изходът е PDF, за да получите всеки етикет, един на страница. |
zpl | За GET, URL-кодирането на ZPL. Кодирайте # като %23. Използвайте POST за всичко дълго. |
С POST, изпратете ZPL като сурово съдържание на заявката или като многочастично поле с име file.
API ключове
Без ключ получавате 3 етикета на ден на IP адрес, достатъчно, за да го опитате. С ключ от таблото за управление, изпратете го в заглавката X-API-Key и ограниченията на плана на вашето работно пространство важат.
curl https://api.openzpl.com/v1/printers/8dpmm/labels/4x6/0/ \ -H "X-API-Key: oz_live_…" --data-binary @label.zpl > label.png
Примери
Всеки изпраща label.zpl, запазва label.pdf и показва съобщението за грешка на API, ако нещо е сбъркано. За PNG, поискайте image/png и добавете индекса на етикета (/0/) към 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"
Заглавия на заявката
| Заглавие | Стойности | По подразбиране |
|---|---|---|
Accept | image/png, application/pdf | PNG |
X-Quality | Grayscale (8-бит, гладки ръбове) или Bitonal (1-бит, по-малки файлове) | Grayscale |
X-Rotation | 0, 90, 180, 270, по посока на часовниковата стрелка | 0 |
X-Language | zpl, epl, tspl, auto: езикът на принтера на тялото. Без него, тяло без ^ или ~ се чете като EPL или TSPL, когато изглежда така. | zpl |
X-API-Key | Ключ за вашето работно пространство, по избор | — |
Ограничения
- 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).
Отговори и грешки
Успешните отговори съдържат X-Total-Count, броя на етикетите, които ZPL произвежда, включително ^PQ копия. Грешките са обикновен текст, който започва с ERROR:.
| Статус | Значение |
|---|---|
| 400 | Параметърът е невалиден, етикетът е прекалено голям или индексът е извън диапазона. |
| 401 | API ключът е неизвестен или е отменен. |
| 406 | Accept заглавието иска формат на изхода, който все още не е наличен. |
| 413 | Тялото е над 1 MB, или ZPL произвежда повече от 50 етикети. |
| 429 | Твърде много заявки или етикети за вашия план. Изчакайте броя секунди в Retry-After. |
| 503 | Етикетът отне повече от 10 секунди за рендериране, или услугата има капацитет. Опитайте отново или намалете плътността или размера. |
Какво рисува двигателят, игнорира или все още не поддържа, можете да намерите на the compatibility page; колко бързо се рендерира, измерено на продукционния сървър, на the benchmarks page.
Шаблони: попълнете запазен дизайн с вашите данни
Проектирайте етикет с {{variables}} плейсхолдъри, запазете го и копирайте ID-то му от таблото: d123 за проект, l45 за запазен етикет. След това вашата система изпраща само данните с 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
Използвайте {"data": {...}} за един етикет или {"rows": [...]} за до 50. Accept дава PDF или PNG, или text/plain запълнения ZPL за изпращане на принтер. Стойностите са ескейпнати, така че данните ви никога не могат да стартират ZPL команда.
Отпечатайте на локален принтер
С print agent, работещ до принтера, POST /v1/print-jobs поставя ZPL в опашка за него и POST /v1/templates/{id}/print попълва запазен дизайн. И двата изискват име на printer и връщат ID на задачата; GET /v1/print-jobs/{id} ви казва дали е отпечатано.
Въпроси
Колко струва API?
Без ключ можете да го тествате с 3 етикета на ден. Безплатен ключ позволява 20 етикета на ден, а paid plans започват от $29 на месец за 100,000 етикета.
Съвместимо ли е с Labelary?
Да: същите пътеки, заглавки и грешки. Променете името на хоста и изпратете вашия ключ, както показва migration guide.
Запазвате ли моите етикети?
Не с API ключ: етикетът е генериран и върнат. privacy page има подробности и крайни срокове.
Може ли AI асистент да го използва?
Да, чрез MCP server: Claude, Cursor и други асистенти могат да рендерират етикети с него.
OpenAPI и Markdown
Същият договор е публикуван като OpenAPI 3.1 и Markdown, за генератори на код и помощници по кодиране.
Стъпка по стъпка ръководства: Python, Node.js, PHP, C#. Преминаване от Labelary: migration guide.