ZPL Web Service API Guide
ZPL Web Service API Guide
4. Examples
> POST /v1/printers/8dpmm/labels/4x6/0/ HTTP/1.1
4.1. Live 4.9. D Language > Host: api.labelary.com
4.2. curl 4.10. C# > Accept: */*
4.3. Postman 4.11. VB.NET > Content-Length: 40
4.4. PowerShell 4.12. ColdFusion > Content-Type: application/x-www-form-urlencoded
4.5. Java 4.13. PHP >
4.6. Python 4.14. Rust > ^xa^cfa,50^fo100,100^fdHello World^fs^xz
4.7. Ruby 4.15. Go Language
4.8. Node.js 4.16. Excel VBA < HTTP/1.1 200 OK
5. Advanced < Content-Type: image/png
< Transfer-Encoding: chunked
5.1. Rotate labels
< Connection: keep-alive
5.2. PDF with multiple labels
< X-Total-Count: 1
5.3. PDF page size and orientation
<
5.4. PDF page layout
< +-----------------------------------------------+
5.5. How many labels?
< | NOTE: binary image data not shown in terminal |
5.6. Print quality
< +-----------------------------------------------+
5.7. Linting
5.8. Data Extraction
6. Other Functionality
6.1. Converting images to ZPL graphics
6.2. Converting TTF fonts to ZPL fonts
1. Introduction
The Labelary ZPL rendering engine is available as an online service, and can be invoked via a simple, easy-to-use RESTful API:
GET http://api.labelary.com/v1/printers/{dpmm}/labels/{width}x{height}/{index}/{zpl}
By default the service returns PNG images, but a variety of output formats are available:
PNG (requested by sending an Accept: image/png request header, or by omitting the Accept request header entirely)
PDF (requested by sending an Accept: application/pdf request header)
IPL (requested by sending an Accept: application/ipl request header)
EPL (requested by sending an Accept: application/epl request header)
DPL (requested by sending an Accept: application/dpl request header)
JSON (requested by sending an Accept: application/json request header, useful for data extraction)
POST http://api.labelary.com/v1/printers/{dpmm}/labels/{width}x{height}/{index}
You can also use POST instead of GET by moving the ZPL out of the URL and into the POST request body. When using POST , the request Content-Type may be either:
application/x-www-form-urlencoded (in which case the request body should contain the raw ZPL to be converted), or
multipart/form-data (in which case the ZPL should be provided in a form parameter named file )
a. Your ZPL is very large (since URLs are limited to roughly 3,000 characters), or
b. You are running into character encoding issues, or
c. Your ZPL contains embedded binary data, or
d. Your ZPL contains sensitive information (since URLs are often logged by proxies and other intermediaries)
2. Parameters
dpmm
The desired print density, in dots per millimeter.
Valid values are 6dpmm , 8dpmm , 12dpmm , and 24dpmm . See your printer's documentation for more information.
width
The label width, in inches. Any numeric value may be used.
height
The label height, in inches. Any numeric value may be used.
index
The label index (base 0).
Some ZPL code will generate multiple labels, and this parameter can be used to access these different labels. In general though, the value of this parameter will be 0 (zero).
Note that this parameter is optional when requesting PDF documents. If not specified, the resultant PDF document will contain all labels (one label per page).
zpl
The ZPL code to render.
Note that if you are using the GET HTTP method and the ZPL contains any hashes (#), they should be encoded (%23) in order to avoid parts of the ZPL being incorrectly interpreted
as URL fragments.
3. Limits
As a shared service, the Labelary API incorporates a number of usage limits which ensure that no single user can negatively impact the workloads of other users:
Maximum 5 requests per second per client. Additional requests result in a HTTP 429 (Too Many Requests) error.
Maximum 50 labels per request. Additional labels result in a HTTP 413 (Payload Too Large) error. See the FAQ for details.
Maximum label size of 15 x 15 inches. Larger labels result in a HTTP 400 (Bad Request) error.
Maximum 10 MB image buffer when generating PNG files. Images requiring a larger memory buffer result in a HTTP 400 (Bad Request) error. See the FAQ for details.
Maximum embedded object size of 2 MB, for e.g. ~DU and ~DY . Larger embedded objects result in a HTTP 400 (Bad Request) error.
Maximum embedded image dimensions of 2,000 x 2,000 pixels, for e.g. ~DG and ~DY . Larger embedded images result in a HTTP 400 (Bad Request) error.
Maximum 2 MB printer memory used for fonts, images and other files. Exceeding this limit results in a HTTP 400 (Bad Request) error. See the FAQ for details.
The image conversion service (image → ZPL) also has the following limits:
Maximum input image file size of 200 KB. Larger files result in a HTTP 400 (Bad Request) error.
Maximum input image dimensions of 2,000 x 2,000 pixels. Larger image sizes result in a HTTP 400 (Bad Request) error.
The font conversion service (TTF font → ZPL) also has the following limits:
Maximum input font file size of 200 KB. Larger files result in a HTTP 400 (Bad Request) error.
Note that these limits may be changed as needed in order to ensure smooth operation of the service for all users.
If these limits are too restrictive for your intended use, you may want to consider licensing Labelary for private on-premise use.
4. Examples
The code snippets and examples below are intended to help you start consuming the Labelary API quickly, regardless of your client-side technology stack. If you have a code sample
that uses a different technology stack, and you'd like to share it with other Labelary users, feel free to email us.
http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/^xa^cfa,50^fo100,100^fdHello World^fs^xz
http://api.labelary.com/v1/printers/12dpmm/labels/3.5x1.5/0/^xa^cfa,50^fo100,100^fdSmaller Label^fs^xz
http://api.labelary.com/v1/printers/6dpmm/labels/4x6/1/^xa^cfa,50^fo100,100^fdFirst Label^fs^xz^xa^cfa,50^fo100,100^fdSecond Label^fs^xz
Using the POST method (with multipart/form-data content), requesting a PDF file instead of a PNG image:
curl --request POST http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/ --form [email protected] --header "Accept: application/pdf" > label.pdf
Invoke-RestMethod `
-Method Post `
-Uri http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/ `
-ContentType "application/x-www-form-urlencoded" `
-InFile label.zpl `
-OutFile label.png
Using the POST method (with application/x-www-form-urlencoded content) to request a PDF file:
Invoke-RestMethod `
-Method Post `
-Uri http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/ `
-ContentType "application/x-www-form-urlencoded" `
-Headers @{"Accept" = "application/pdf"} `
-InFile label.zpl `
-OutFile label.pdf
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
var uri = URI.create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
var request = HttpRequest.newBuilder(uri)
.header("Accept", "application/pdf") // omit this line to get PNG images back
.POST(BodyPublishers.ofString(zpl))
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, BodyHandlers.ofByteArray());
var body = response.body();
if (response.statusCode() == 200) {
var file = new File("label.pdf"); // change file name for PNG images
Files.write(file.toPath(), body);
} else {
var errorMessage = new String(body, StandardCharsets.UTF_8);
System.out.println(errorMessage);
}
import requests
import shutil
# adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
url = 'http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/'
files = {'file' : zpl}
headers = {'Accept' : 'application/pdf'} # omit this line to get PNG images back
response = requests.post(url, headers = headers, files = files, stream = True)
if response.status_code == 200:
response.raw.decode_content = True
with open('label.pdf', 'wb') as out_file: # change file name for PNG images
shutil.copyfileobj(response.raw, out_file)
else:
print('Error: ' + response.text)
require 'net/http'
# adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
uri = URI 'http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/'
http = Net::HTTP.new uri.host, uri.port
request = Net::HTTP::Post.new uri.request_uri
request.body = zpl
request['Accept'] = 'application/pdf' # omit this line to get PNG images back
response = http.request request
case response
when Net::HTTPSuccess then
File.open 'label.pdf', 'wb' do |f| # change file name for PNG images
f.write response.body
end
else
puts "Error: #{response.body}"
end
var fs = require('fs');
var request = require('request');
var options = {
encoding: null,
formData: { file: zpl },
// omit this line to get PNG images back
headers: { 'Accept': 'application/pdf' },
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
url: 'http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/'
};
import std.stdio;
import std.net.curl;
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
auto url = "http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/";
auto zpl = "^xa^cfa,50^fo100,100^fdHello World^fs^xz";
void main() {
auto conn = HTTP();
conn.addRequestHeader("Accept", "application/pdf"); // omit this line to get PNG images back
auto label = url.post!ubyte(zpl, conn);
if (conn.statusLine.code == 200) {
label.toFile("label.pdf"); // change file name for PNG images
} else {
writeln(conn.statusLine.toString());
}
}
4.10. C# Example
A C# example that uses a POST request to convert a ZPL string to a PDF file:
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
var request = (HttpWebRequest) WebRequest.Create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
request.Method = "POST";
request.Accept = "application/pdf"; // omit this line to get PNG images back
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = zpl.Length;
try {
var response = (HttpWebResponse) request.GetResponse();
var responseStream = response.GetResponseStream();
var fileStream = File.Create("label.pdf"); // change file name for PNG images
responseStream.CopyTo(fileStream);
responseStream.Close();
fileStream.Close();
} catch (WebException e) {
Console.WriteLine("Error: {0}", e.Status);
}
' adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
Dim request As HttpWebRequest = WebRequest.Create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/")
request.Method = "POST"
request.Accept = "application/pdf" ' omit this line to get PNG images back
request.ContentType = "application/x-www-form-urlencoded"
request.ContentLength = zpl.Length
Try
Dim response As HttpWebResponse = request.GetResponse()
Dim responseStream As Stream = response.GetResponseStream()
Dim fileStream As Stream = File.Create("label.pdf") ' change file name for PNG images
responseStream.CopyTo(fileStream)
responseStream.Close()
fileStream.Close()
Catch e As WebException
Console.WriteLine("Error: {0}", e.Status)
End Try
<cfoutput>
<cfset zpl="^xa^cfa,50^fo100,100^fdHello World^fs^xz">
<!-- change type to "image/png" to get PNG images -->
<cfset type="application/pdf">
<!-- adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary -->
<cfhttp url="http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/" method="post" result="result">
<cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded">
<cfhttpparam type="header" name="Accept" value="#type#">
<cfhttpparam type="body" value="#zpl#">
</cfhttp>
<cfcontent variable="#result.Filecontent#" type="#type#" reset="true" />
</cfoutput>
<?php
$curl = curl_init();
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
curl_setopt($curl, CURLOPT_URL, "http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $zpl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Accept: application/pdf")); // omit this line to get PNG images back
$result = curl_exec($curl);
curl_close($curl);
?>
use reqwest::Client;
use std::io::Cursor;
use std::fs::File;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
let url = "http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/";
let response = Client::new()
.post(url)
.body(zpl)
.header("Accept", "application/pdf") // omit this line to get PNG images back
.send().await?;
if response.status().is_success() {
let mut file = File::create("label.pdf")?; // change file name for PNG images
let mut content = Cursor::new(response.bytes().await?);
std::io::copy(&mut content, &mut file)?;
} else {
let error_message = response.text().await?;
eprintln!("{}", error_message);
}
Ok(())
}
package main
import (
"os"
"io"
"io/ioutil"
"log"
"bytes"
"net/http"
)
func main() {
client := &http.Client{}
response, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer response.Body.Close()
if response.StatusCode == http.StatusOK {
file, err := os.Create("label.pdf") // change file name for PNG images
if err != nil {
log.Fatalln(err)
}
defer file.Close()
io.Copy(file, response.Body)
} else {
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatalln(err)
}
log.Fatalln(string(body))
}
}
Sub Convert()
'adjust print density (8dpmm), label width (4 inches), label height (6 inches), and label index (0) as necessary
u = "http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/"
tempFile = Environ("Temp") & "\excel-label-temp.png"
Set ws = ActiveWorkbook.Sheets("Sheet1")
Set http = CreateObject("MSXML2.ServerXMLHTTP")
Set stream = CreateObject("ADODB.Stream")
stream.Type = 1 'adTypeBinary
End Sub
5. Advanced
Some advanced features provided by the Labelary API:
If this is the case, you can ask Labelary to rotate the label image by adding a X-Rotation HTTP header to the request. The value of this header should be the number of degrees to
rotate the label clockwise, and may be one of 0 , 90 , 180 or 270 .
For example, instead of sending your request to this URL, which returns the label at index 0 (the first label):
http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/
You can omit the index and instead send your request to this URL:
http://api.labelary.com/v1/printers/8dpmm/labels/4x6/
The X-Page-Size HTTP header tells Labelary to use a specific PDF page size. Valid values are Letter , Legal , A4 , A5 and A6 .
The X-Page-Orientation HTTP header tells Labelary to use a specific orientation of the specified page size. Valid values are Portrait and Landscape .
Note that these headers can only be used with PDF requests.
The X-Page-Layout HTTP header tells Labelary to lay out the labels on the PDF pages in a tabular format. The header value must be in the form <columns>x<rows> . For
example, a value of 2x3 would generate a PDF file with 6 labels per page, arranged in 2 columns and 3 rows.
The X-Page-Align HTTP header tells Labelary how to align the labels horizontally. Valid values are Left , Right , Center and Justify . The default value is Justify , which
distributes extra horizontal whitespace evenly across the page.
The X-Page-Vertical-Align HTTP header tells Labelary how to align the labels vertically. Valid values are Top , Bottom , Center and Justify . The default value is Justify ,
which distributes extra vertical whitespace evenly across the page.
Note that these headers can only be used with PDF requests.
Grayscale generates 8-bit grayscale images suitable for electronic viewing and printing on high-density printers. This is the default setting.
Bitonal generates 1-bit monochrome images suitable for printing on low-density printers. It also generates smaller files (useful when file size is more important than output quality).
5.7. Linting
It is possible to ask Labelary to check your ZPL for potential errors while rendering the ZPL. This process is known as linting. You can enable the Labelary linter by adding the X-
Linter HTTP header to your request. Valid values are On (to enable the linter), and Off (to disable the linter). The linter is disabled by default.
Once the linter is enabled, warnings will be returned in the X-Warnings HTTP response header. The maximum number of warnings that will be returned is 20. Additional warnings (if
any) will not be returned. Warnings will be returned in pipe-delimited format, and each warning will include 5 attributes:
1. The byte index of the ZPL section which triggered the warning (integer, never empty)
2. The byte size of the ZPL section which triggered the warning (integer, never empty)
3. The name of the ZPL command which triggered the warning (string, may be empty if the warning is not associated with a specific command)
4. The parameter number of the command parameter which triggered the warning (integer, may be empty if the warning is not associated with a specific parameter)
5. The warning message (string, never empty)
As an example, the following HTTP response header indicates that the submitted ZPL generated 2 warnings:
X-Warnings: 303|1|^GB|2|Value 1 is less than minimum value 3; used 3 instead|591|3|||Ignored unrecognized content
The first warning, starting at byte index 303 and extending for 1 byte, indicates that the second parameter of the ^GB command used a value that was too small. The second warning,
starting at byte index 591 and extending for 3 bytes, indicates that some unrecognized content was found between ZPL commands. The command name and parameter number for
the second warning are empty, since the warning was not generated inside any specific ZPL command.
In some cases you may wish to extract data from your ZPL for further processing. In these scenarios it is possible to ask Labelary to provide a list of output labels and data fields in
JSON format by simply sending an Accept: application/json HTTP request header.
The resultant JSON will contain all text displayed on the labels. It will not contain information about lines, rectangles, circles, or other graphics. The output JSON will contain the
human-readable text for any barcodes, but will not contain the actual data encoded in the barcode symbols. Barcodes without human-readable text above or below the barcode will
therefore not be included in the generated JSON. The order of the data fields in the output JSON will always match the field definition order in the ZPL.
Below is an example input ZPL template which defines two labels, each of which contains two data fields, and the corresponding output JSON:
^XA
^FT50,50^A0,50^FDField 1^FS
^FT50,150^A0,50^FDField 2^FS
^XZ
^XA
^FT50,50^A0,50^FDField 3^FS
^FT50,150^A0,50^FDField 4^FS
^XZ
{
"labels": [
{ "fields": [ { "x": 50, "y": 50, "data": "Field 1" }, { "x": 50, "y": 150, "data": "Field 2" } ] },
{ "fields": [ { "x": 50, "y": 50, "data": "Field 3" }, { "x": 50, "y": 150, "data": "Field 4" } ] }
]
}
6. Other Functionality
In addition to conversion from ZPL to other file formats, the Labelary API also provides a few other useful endpoints:
POST http://api.labelary.com/v1/graphics
The submitted Content-Type must be multipart/form-data , with a file parameter containing the image to be converted.
By default, this endpoint returns ZPL, but the following output formats are available:
ZPL (requested by sending an Accept: application/zpl request header, or by omitting the Accept request header entirely)
JSON (requested by sending an Accept: application/json request header)
EPL (requested by sending an Accept: application/epl request header)
IPL (requested by sending an Accept: application/ipl request header)
DPL (requested by sending an Accept: application/dpl request header)
The following sample curl command converts a local file named image.png to ZPL graphics:
The following sample curl command converts a local file named image.png to EPL format:
curl --request POST http://api.labelary.com/v1/graphics --form [email protected] --header "Accept: application/epl" > image.epl
POST http://api.labelary.com/v1/fonts
If no path is provided, a printer path is chosen for you automatically. If no name is provided, a shorthand font name is not associated with the font.
The chars parameter allows you to subset the font. Subsetting is the process of limiting the number of characters that the font is able to render in order to reduce its size. For
example, if you plan to use your custom font to print only numbers, then setting chars to 0123456789 will subset the font accordingly, yielding a much smaller ZPL snippet. Note
that some fonts do not allow subsetting. If you try to subset a font which does not allow it, you will receive an error.
IMPORTANT: Always check your font license to make sure that your intended use falls within the terms of the license.
The following sample curl command converts a local font file named Montserrat-Bold.ttf to ZPL font format:
The following sample curl command converts a local font file named Montserrat-Bold.ttf to ZPL font format, configures a shorthand font name for the font, and subsets the
font to be able to print only uppercase letters:
curl --request POST http://api.labelary.com/v1/fonts --form [email protected] --form name=Z --form chars=ABCDEFGHIJKLMNOPQRSTUVWXYZ > font.zpl