Audience

Use the SendFileToPrinter API for Your Cloud-Based Printing Needs

Why use the SendFileToPrinter API?

Zebra Data Services has recently released a cloud-based REST API for Zebra Print DNA printers featuring our powerful Link-OS operating system. It is called SendFileToPrinter API. This is good news for developers who want to take advantage of cloud-based printing without worrying about how to connect the printers securely to the cloud. The SendFileToPrinter API allows developers to send content quickly, easily and securely in one file to a Print DNA printer via the powerful Zebra Data Services platform*.

Here are some of the advantages of the SendFileToPrinter API.

  1. The SendFileToPrinter is a REST API that is language & platform agnostic, which means it can be used with any programming languages on any platform, because it is simply a matter of a HTTPS Multipart POST request. You simply choose the programming language and platform that you are familiar or comfortable with when using this API.
  2. The connection from your printer to Zebra Data Services cloud is secured through SSL/TLS. There is no need to reinvent the wheel to create a secured connection yourself. You can be assured that your printer is safely and securely connected to the Zebra Data Services cloud.
  3. Since it is cloud-based, you can print labels and receipts or send content, up to 10 MB in size, in a file to any connected Print DNA printer. There is no need to tether a printer through USB or Bluetooth to a computer or a mobile device. This provides great flexibility for your application.

What can the SendFileToPrinter API do?

This SendFileToPrinter API is unidirectional. It is a simple, yet very powerful API. It can be used to send a wide variety of content to the printer, including commands found in the ZPL Programming Guide*. For example, you can use this API to print labels or receipts by sending the ZPL format commands in a file format to the printer. You can use this API to download objects, such as fonts, graphics, or Wi-Fi® certificates, in a file format to the printer. This API can also be used to configure the printer by sending Set-Get-Do (SGD) configuration commands or JSON configuration strings in a file format to the printer. You can send any allowed content to the printer through this API. You have the option to send the content to one or multiple printers in one API call.

If you are familiar with Zebra ZPL format commands, you can create the label or receipt with ZPL and send the ZPL content in a file straight away with this API to a printer to print. If you are unfamiliar with ZPL, then you can use ZebraDesigner for Developers 3, a free tool, to create your design and generate the ZPL for you.

Since the SendFileToPrinter is a unidirectional API, do not expect to use this API to retrieve anything out from the printer. For example, you cannot retrieve the printer settings with this API by sending the related SGD or JSON commands, because this API does not return such content. However, the caller of this API gets acknowledged on whether the API call is successful or not through the response each time.

How to get started?

To use the SendFileToPrinter API, you need an API key and a Print DNA printer registered with the Zebra Data Services cloud platform. Here are the How-To articles to help you get started.

Apply for Zebra Developer Account and API Key

Getting Started with Zebra Data Services – A step-by-step guide on how to open a developer account, how to add API packages to your account, how to add an app and generate the API key, etc. on the Zebra Data Services developer portal. 

Notes:

  1. To gain access to the SendFileToPrinter API, you'll need to add a SendFileToPrinter package (Free or PPC) and select the package in your account when you create an app to generate the API key.
  2. Using the same API key for both Free and Pay Per Call (PPC) packages are treated as an API call to both packages at the same time. It is recommended to use a separate API key for the SendFileToPrinter (Free) and SendFileToPrinter (PPC) packages.

Printer Setup

Printer Setup Guide – A step-by-step guide on how to configure the network connection, the Weblink endpoint to the Zebra Data Services platform, and how to get the tools required to send the JSON configuration file to a Print DNA printer. For more details about Weblink, refer to the Using Weblink section in ZPL Programming Guide

Use the following JSON string for the Weblink configuration of your Print DNA printer. Replace the value of the query parameter r (The r must be in lowercase) with the printer enrollment code, an auto-generated code by clicking on Add Device button on My Devices page at https://developer.zebra.com/my-devices. To access My Devices page, you'll need to log into your developer account.

{}{
"weblink.logging.max_entries":"500",
"weblink.ip.conn1.location":"https://savanna-device.zpc.zebra.com/weblink/connect?r=a6f47ecf23e841c8f5c94f82c3d2ede8",
"device.reset":"1"
}

The above JSON string can be sent to the printer as a file by using the Printer Setup Utilities for Windows, Android or iOS.

Notes:

  1. There should be no space between the braces in the above JSON string, i.e. no spaces in "{}{".
  2. You can have two Weblinks configured at the same time on a printer, i.e. weblink.ip.conn1.location and weblink.ip.conn2.location. However, they cannot point to the same Weblink URL. If they point to the same Weblink URL, they will cancel each other’s connection and cause a ping-pong effect. Refer to the Using Weblink section in ZPL Programming Guide for additional info.
  3. Zebra Data Services only supports one Weblink connection per Print DNA printer at a time. You can only use one Weblink on the printer to connect to Zebra Data Services. The other Weblink can be used for other services.
  4. Make sure the previous Weblink configuration is not unintentionally overwritten. The following commands can be used to check if the Weblink configurations are already in use, before overwriting either one of them.
{}{
"weblink.ip.conn1.location":null,
"weblink.ip.conn2.location":null
}
! U1 getvar "weblink.ip.conn1.location"
! U1 getvar "weblink.ip.conn2.location"

Unregister and disconnect the printer

{}{
"weblink.ip.conn1.location":"",
"device.reset":"1"
}

By passing an empty string ("") to the weblink.ip.conn1.location, the above JSON configuration string will remove the Weblink URL and disconnect the Weblink connection from weblink.ip.conn1.location. You can do the same for weblink.ip.conn2.location, if it is configured for connecting to the Zebra Data Services cloud platform. Note: When removing or reconfiguring a Weblink URL, please be cautious to not impact or disrupt other applications use of the Weblink connection.

Test Print

Once you complete the steps in Getting Started with Zebra Data Services and Printer Setup Guide, you can send the following HTTPS request in cURL to the printer. It will print out “Hello World” on a label, assuming you have the “^XA ^FO50,50^ADN,36,20^FDHello World^FS ^XZ” ZPL string (without the double quotes) stored in a file called HelloWorld.txt. Note: You'll need to replace the API key and the tenant account number in the request header and the printer’s serial number of the sn key-value pair in the request body with your values in order to see the action. The tenant account number can be retrieved from the Tenant Service.

$ curl -H "apikey: yourApiKey" -H "tenant: yourTenantAccountNumber" \
       -F "sn=printerSerialNumber" -F "zpl_file=@HelloWorld.txt" \
       https://api.zebra.com/v2/devices/printers/send

Note: If you want to send the HelloWorld.txt file to more than one printer, you simply add additional sn key-value pairs in the request body. The following cURL, for example, will print “Hello World” from two printers.

$ curl -H "apikey: yourApiKey" -H "tenant: yourTenantAccountNumber" \
       -F "sn=printerSerialNumber_1" \
       -F "sn=printerSerialNumber_2" -F "zpl_file=@HelloWorld.txt" \
       https://api.zebra.com/v2/devices/printers/send

If you prefer, you can also use Postman instead of cURL to do the test print.

NOTES:

  1. The maximum size of the file supported by the SendFileToPrinter API is 10MB at this moment. If the file size is larger than 10MB, unexpected error may occur.
  2. Only one file can be sent at a time. If multiple files are specified with multiple zpl_file key-value pairs in the request body, only one file is accepted and sent. All the other files in the request will be ignored.
  3. The file content of ZPL label, receipt format, or downloadable object must be complete. It cannot be divided into partial formats in multiple files to send, i.e. concatenating multiple files is not supported.
  4. It is recommended not to call the API to send file or content to the printer while the printer is updating its operating system, as the delivery of the file or the content is not guaranteed during the printer operating system update.

*Max file size is 10 MB

Submitted by SSi1 on September 08, 2021 Permalink

1. Ensure that the multipart form body complies with the format below, so that it can be parsed correct by the backend. Any other headers in each part are not allowed and will result in a bad request error.

--203fab52-5a95-4e51-9e5c-53248aae2256
Content-Disposition: form-data; name="sn"

XXZJJ174600934
--203fab52-5a95-4e51-9e5c-53248aae2256
Content-Disposition: form-data; name="zpl_file"; filename="HelloWorld.txt"
Content-Type: text/plain

^XA^FO50,50^ADN,36,20^FDHello World!^FS^XZ
--203fab52-5a95-4e51-9e5c-53248aae2256--

2. Here are a few examples available on GitHub of how to use this API

  • JavaScript:

PrintFromCloud - A JavaScript example demonstrates how to use the SendFileToPrinter API to print labels and receipts from anywhere to any Link-OS printers connected to the Zebra Data Services cloud platform.

  • Java

Use the Zebra SendFileToPrinter Multipart BodyPublisher (ZebraSftpMpBodyPublisher.java), which is based on the java.net.http.HttpRequest package,  for your convenience. The following code snippet shows how to use ZebraSftpMpBodyPublisher.java.

// Create URI from the URL of SendFileToPrinter API
URI uri = URI.create("https://api.zebra.com/v2/devices/printers/send");

String apikey = "z2GI9d7UAlMLMDMEE7qA6RVK1GAigRJJ"; // Replace it with your apikey
String tenant = "695315b271dd374c76fad074e6b1f8cf"; // Replace it with your tenant ID
String sn = "XXZJJ174600912";                       // Replace it with your printer serial number

// Example ZPL file containing - "^XA ^FO50,50^ADN,36,20^FDHello World^FS ^XZ"
Path zplFilePath = Paths.get("C:\\Users\\john\\HelloWorld.txt"); // Replace it with your ZPL file path

// Use ZebraSftpMpBodyPublisher.java
ZebraSftpMpBodyPublisher publisher 
                    = new ZebraSftpMpBodyPublisher().addSn(sn).addSn(sn).addSn(sn).setZplFilePath(zplFilePath);

HttpRequest request = HttpRequest.newBuilder().uri(uri).header("apikey", apikey).header("tenant", tenant)
                      .header("Content-Type", "multipart/form-data; boundary=" + publisher.getBoundary())
                      .POST(publisher.build()).build();

HttpClient httpclient = HttpClient.newBuilder().build();
HttpResponse response = httpclient.send(request, BodyHandlers.ofString());

System.out.println(response.body());
  • C#

Use the Zebra SendFileToPrinter Multipart BodyPublisher (ZebraSftpMpBodyPublisher.cs), which is based on the System.Net.Http,  for your convenience. The following code snippet shows how to use ZebraSftpMpBodyPublisher.cs.

string sftpPostUrl = "https://api.zebra.com/v2/devices/printers/send"; // The endpoint of the SendFileToPrinter API
string apikey = "z2GI9d7UAlMLMDMEE7qA6RVK1GAigRJJ";         // Replace it with your apikey
string tenant = "695315b271dd374c76fad074e6b1f8cf";         // Replace it with your tenant ID
string sn1 = "XXZJJ174600912";                              // Replace it with your printer serial number
string sn2 = "XXZJJ174600913";                              // Replace it with your printer serial number
string zplFilePath = @"/Users/john/Desktop/HelloWorld.txt"; // Replace it with your ZPL file path

HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("apikey", apikey); // Add the apikey to the header
httpClient.DefaultRequestHeaders.Add("tenant", tenant); // Add the tenant ID to the header

// Use ZebraSftpMpBodyPublisher to compose the form data
MultipartFormDataContent formData = 
                  new ZebraSftpMpBodyPublisher().AddSn(sn1).AddSn(sn2).SetZplFilePath(zplFilePath).Build();

// Post the form data
HttpResponseMessage response = await httpClient.PostAsync(sftpPostUrl, formData);

response.EnsureSuccessStatusCode();
httpClient.Dispose();
string description = response.Content.ReadAsStringAsync().Result;
  • OkHttp

You can use OkHttp open source from Square. By default, however, the Content-Length header is added to each part in the multipart form data, which will result in an error thrown back from the server of SendFileToFile API. We need to remove this unwanted header from the request body before posting the request to the server. Here is the code to remove the Content-Length headers from the multipart form body.

private static RequestBody remvoeContentLengthHeaders(final RequestBody original) {
    return new RequestBody() {

        @Override
        public @Nullable
        MediaType contentType() {
            return original.contentType();
        }

        @Override
        public void writeTo(final BufferedSink sink) throws IOException {
            final Buffer buffer = new Buffer();
            original.writeTo(buffer);
            String reqBodyStr = buffer.readUtf8();

            // Remove the Content-Length headers for all parts in the multipart form body
            String reqBodyNoContentLengthStr = reqBodyStr.replaceAll("(?i)\r?\ncontent-length:\\s*[0-9]+", "");
            sink.writeUtf8(reqBodyNoContentLengthStr);
        }
    };
}

Here is the example code of posting the request without the Content-Length headers.

String sn = "XXZJJ174600912";
String url = "https://api.zebra.com/v2/devices/printers/send";
String apikey = "z2GI9d7UAlMLMDMEE7qA6RVK1GAigRJJ";
String tenant = "695315b271dd374c76fad074e6b1f8cf";

File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/HelloWorld.txt");

// OKHttp client
OkHttpClient client = new OkHttpClient.Builder()
        .build();

RequestBody fileReqBody = RequestBody.create(file, MediaType.parse("text/plain"));

RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("sn", sn)
        .addFormDataPart("zpl_file", "HelloWorld.txt", fileReqBody)
        .build();

Request request = new Request.Builder()
        .url(url)
        .post(remvoeContentLengthHeaders(requestBody)) // Remove the Content-Length headers
        .addHeader("apikey", apikey)
        .addHeader("tenant", tenant)
        .build();

try {
    Response response = client.newCall(request).execute();
    System.out.println(response.body().string());
} catch (Exception e) {
    // Do something
    System.out.println(e.toString());
}

 

Submitted by ifaust@ipsiscan.com on September 14, 2021 Permalink

Hello,
It appears that this currently only works using ZPL code. I would like to leverage PDF Direct with your API. Is there any way to send a PDF to the printer through the API?
Thank you.

Submitted by sing@virtualki… on April 28, 2021 Permalink

Thanks Steven,
This blog is very helpful.
And we would love to use the sendFileToPrinter API.
One issue we encounter is the CORS error if we try to call the API from a web app (i.e. React).
Any suggested solution ?
By any chance we can set Access-Control-Allow-Origin: * on the API server side ?
Best regards,
Sing

Submitted by Hussain Hussain on April 30, 2021 Permalink

I am getting
{"error":"invalid_token","error_description":"Cannot convert access token to JSON"}
any help?