Use the SendFileToPrinter API for Your Cloud-Based Printing Needs
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.
- 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.
- 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.
- 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:
- 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.
- 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:
- There should be no space between the braces in the above JSON string, i.e. no spaces in "{}{".
- 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.
- 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.
- 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:
- 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.
- 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.
- 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.
- 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
Steven Si
34 Replies
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());
}
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.
The current implementation of the SendFileToPrinter API doesn't support PDF unfortunately. The PDF support is on the back burner of the plan of this API.
Yes, the PDF print is now supported by the SendFileToPrinter API from the Link-OS 6.7 onwards. The support is based on the PDF Direct, which needs to be enabled. See this article on how to download and enable the PDF Direct: Announcement | Printers Include Free PDF Direct with Link-OS 6.3. To use the PDF direct over the SendFileToPrinter API, make sure the printer is on the Link-OS 6.7 or later.
Hi,
I have enabled PDF Direct for my printermodel # ZD410 , LinkOS: 6.4,
! U1 getvar "apl.enable"
- "pdf"
but it does not print PDFs via SendFileToPrinter API.
When I do print - nothing is happening and response from API call is SUCCESS:
{"responses":[{"guid":"01********************","sn":"**********","status":"SUCCESS"}],"status":"SUCCESS"}
Hi Tair,
Make sure you have the latest PDF emulator installed on your ZD410. The latest PDF emulator is v2.08-02. You can download the latest version from the ZD410 support webpage. Use the following SGD to check the version installed on your printer.
! U1 getvar "apl.installed_versions"
That's odd. Then try the apl to get everything for the emulation settings
! U1 getvar "apl"
its shows version 2.08-02 but under apl.version
apl.enable : pdf , Choices: apl-e,apl-m,apl-s,pdf,none
apl.framework_version : 1.4
apl.version : 2.08-02
apl.settings :
apl.o.
apl.o.graphics_byte_width : , Choices: 0-255
Hi Tair,
Just realized that there was a bug in the Link-OS v6.6 and earlier that prevents the PDF print over the websocket, which is used by the SendFileToPrinter API for cloud-based printing. The bug was fixed in the Link-OS v6.7. However, the ZD410 has been discontinued and cannot be upgraded beyond the Link-OS 6.4 unfortunately. Sorry, you cannot print the PDF on the ZD410 via the SendFileToPrinter API. You may want to upgrade to the ZD411 model, which is a replacement of the ZD410.
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
I am getting
{"error":"invalid_token","error_description":"Cannot convert access token to JSON"}
any help?
Can I use this API with the ZD421 printer? Is there a list of printers that can be connected this way through the cloud?
I was chatting with Zebra support and the rep said that the ZD421 is not possible to allow cloud printing. Is this true? Reading the spec sheet it says that the ZD421 is Print DNA compatible and runs the Link-OS Operating System which this API seems to require.
Can someone please confirm if I can use the SendFileToPrinter API to print to the ZD421?
That put me on the right track, I succeeded, thank you so much!
For anyone else who works with Power Automate: This did the trick. https://durasyst-my.sharepoint.com/:i:/g/personal/j_jansma_durasyst_nl/…
And have a look at this thread: https://powerusers.microsoft.com/t5/Using-Connectors/Using-HTTP-POST-wi…
I am unfamiliar with the tool you are using and don't see the form-data for the body on your screenshot. If you just want to test the SendFileToPrinter API, please try to use the Postman. Under the Body tab, choose the form-data. Select the file as the type for the key zpl_file and the text as the type for the key sn.
Wow what a quick reply, thank you!
Hmm.. Problem here is that I'm kind of limited to the functions that are offered by the platform I'm using (Power Automate).
Is there a possibility to just post this miltipart form-data as raw text? Had a similar situation before and it worked.
https://durasyst-my.sharepoint.com/:i:/g/personal/j_jansma_durasyst_nl/…
This attempt didn't succeed.
Hi Jelle,
The endpoint of the SendFileToPrinter doesn't accept JSON as the payload. It only accepts the multipart/form-data as the payload. For the part of the zpl_file, however, you can have the SGD commands in JSON format as the file content to send to the printer. This is the only legitimate JSON the printer accepts. For the details of the JSON equivalent of the SGD commands, please refer to the JSON section of the ZPL manual.
Hi Steven,
I'm looking for an example of a JSON payload for a HTTP request to this endpoint. I'm not much of a programmer so I have some trouble to translate these examples above, especially regarding the zpl file.
I've searched the internet for examples but couldn't find any. Would really appreciate if you could help me out!
Kind regards,
Jelle
I receive the following response, but the label is not coming out. I have been using this API for months now and it stopped printing today. Any ideas on what the issue could be?
{"responses":[{"guid":"01GWxxxxxxxxxxxxxxxxx","sn":"D7xxxxxxxxxxx","status":"SUCCESS"}],"status":"SUCCESS"}
Thank you in advance!
Hey Steven I was wondering, in JavaScript, instead of attaching a ZPL file, is it possible to send a string of raw ZPL. I'm looking to have my own HTML form data populate a label. Thanks again for all your help setting up!
The SendFileToPrinter API requires a file and won't work with a ZPL string. In JavaScript, we can easily attach a ZPL string as a Blob to the form data.
fd.append("zpl_file", new Blob([zpl], {type: 'text/plain'})); // Create a blob as file to send.
Refer to the JavaScript example code in the PrintFromCloud on GitHub.
Hi there. Why do you think I get an Internal Server Error with this request:
"uri": "https://api.zebra.com/v2/devices/printers/send",
"method": "POST",
"headers":
"tenant": "<Removed>",
"apikey": "<Removed>",
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="sn"
D8N221111111
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="zpl_file"; filename="CheckInLabel.txt"
Content-Type: text/plain
^XA^FO50,50^ADN,36,20^FDHello World!^FS^XZ
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Without seeing the code, it's hard to tell. In general, we will get an internal server error, if the the request cannot be parsed properly. The request cannot be sent as a plain text. It has to be sent as a multipart form-data with a file element for the ZPL. When using 3rd party API to create the multipart form-data, some API may add addition headers for each part inside the multipart form-data. These additional headers need to be disabled, otherwise, the server may not be able to parse these additional headers and throw out an internal error.
So after several hours of trial and error (and some help from Reddit), I ended up getting this to work. In this case, we are using Microsoft Power Automate to send the HTTP request to the SendFileToPrinter API. When using Power Automate (or Microsoft Logic Apps), even though the request content type is multipart form data, there is a specific JSON format that has to be used in the body of the HTTP call from Power Automate.
I wanted to post it here for reference regarding using Power Automate to communicate with the SendFileToPrinter API.
In your Power Automate flow, enter your ZPL code into a Compose action:
Then, in your HTTP action, choose POST as the method and enter the API endpoint (https://api.zebra.com/v2/devices/printers/send) in the URI field. In the headers section, enter the tenant and apikey headers with your info, and then enter this into the body of the request (Make sure to enter your printer's serial number):
{
"$content-type": "multipart/form-data",
"$multipart": [
{
"headers": {
"Content-Disposition": "form-data; name=\"sn\""
},
"body": "<Your Printer SN>"
},
{
"headers": {
"Content-Disposition": "form-data; name=\"zpl_file\"; filename=\"zplfile.txt\""
},
"body": @{binary(outputs('Compose'))}
}
]
}
When you're done, it should look like this in Power Automate:
In the body, we're using the binary() function to convert the ZPL text from the Compose action into a "file" that the API will understand. This should be all you need to send a print job via HTTP to your API connected printer using Power Automate!
Thank you for sharing the details on integrating the SendFileToPrinter API with the Power Automate. This is great.
Hi, everything makes sense apart from the "Header" block of code. Do you need that?
This is truly a blessing
I am not familiar with ZPL so I am trying to get the configuration together. I was planning to look for help with Power Automate once I had a successful test print. No hunt needed you have already shared 'how'. Love it!
I am struggling to get the printer to print anything. The connection shows my config URI when I check the printer
but I do not see any devices in enrolled devices My Devices | Developer Portal (zebra.com).
And so that is why I get this error when I try to test
{"fault":{"faultstring":"Execution returned an error result","detail":{"errorcode":"flow.execution.ExecutionReturnedFailure"}}}
I also have my Power Automate ready thanks to your guide but when I try to run it, it just hangs
Hi Steven, in the web app I'm developing, there is a bulk printing feature. For example, a user can select a list of customer IDs to print them as barcodes all at once. I noticed that under the article's notes section I see that 'Only one file can be sent at a time.'.
Does that mean I cannot use the SendFileToPrinter API for my particular bulk printing feature? If so, is there an alternative?