Sign In
Products
ZPL PreviewBarcode GeneratorImage → ZPLZPL cheat sheetLabel DesignerTemplate Gallery
Developers
API QuickstartAPI ReferenceMCP ServerBulk GenerationWebhooksSDKs & ExamplesLimitsOn-Premise
Solutions
Logistics & ShippingE-CommerceERP & WMSManufacturingRetailHealthcare & LaboratoryAll solutions
Tools
ZPL Diagnostics HubZPL DebuggerSize & DPI AnalyzerDPI ConverterBarcode fit calculatorShipping Label AnalyzerFont InspectorOrientation DebuggerCalibration AssistantPrinter Compatibility CheckerBarcode Readability CheckerPrinter Language DetectorThermal Printer Test PackZPL ToolsEPL ToolsTSPL ToolsCPCL ToolsAll ToolsGuidesPricing
Language
EnglishTürkçeDeutsch
HomeGuidesUPS ZPL labels: request, preview and fix
Guides › UPS ZPL labels: request, preview and fix

UPS ZPL labels: request, preview and fix

Published:

Result

The UPS Shipping API returns a thermal label as base64 ZPL, one per package, when the request asks for it. Compared with FedEx the request is smaller — an image format code and a stock size — and there is no resolution field at all, which moves one important question (which density are the dots written for?) from the request to the file. This page lists the fields, the path to the label in the response and the checks to run before printing. The rules that apply to every carrier label are in working with carrier ZPL labels; the FedEx counterpart is FedEx ZPL labels.

Field names and values below were read from the UPS Shipping API OpenAPI specification that UPS publishes on GitHub, on 2026-09-14. They change between API versions; confirm them against the current specification before you rely on them. Labelixa is not affiliated with UPS — this is a workflow description, not an integration.

The request fields that shape the ZPL

The call is POST /shipments/{version}/ship — against wwwcie.ups.com for the Customer Integration Environment and onlinetools.ups.com for production. The label is controlled by ShipmentRequest.Shipment.LabelSpecification:

"LabelSpecification": {
  "LabelImageFormat": { "Code": "ZPL" },
  "LabelStockSize": { "Height": "6", "Width": "4" }
}

There is no resolution field. The specification does not say which density the ZPL is written for, so do not assume one: read it from the file (below).

Where the label is in the response

The path is ShipmentResponse.ShipmentResults.PackageResults[] — one entry per package, each with its TrackingNumber and a ShippingLabel object whose GraphicImage is the base64 label and whose ImageFormat.Code confirms the format actually returned. The specification notes that from version v2403 package results are always an array, while older versions return a bare object when there is a single package — a classic cause of "works with one parcel, breaks with two".

jq -r '.ShipmentResponse.ShipmentResults.PackageResults[0].ShippingLabel.GraphicImage'    response.json | base64 -d > label.zpl
head -c 40 label.zpl          # ^XA expected

Two more fields matter for thermal output. InternationalSignatureGraphicImage is returned for non-US shipments in EPL2, ZPL and SPL — one image per shipment, in the first package result — and is a second label to print, not an attachment to ignore. HTMLImage is only returned for GIF and PNG, so its absence with ZPL is normal. The specification also notes that for multi-piece COD shipments the first package's label is always GIF, whatever format was requested — check ImageFormat.Code per package instead of assuming.

Find the density, then preview

Because the request carries no resolution, the only reliable source is the file. The size and DPI analyzer reads the declared width and length out of the ZPL and reports the density that makes them a 4×6 (or 4×8) label; if the file does not declare them, it says so rather than guessing. Then preview at that density and stock:

curl -X POST "https://api.labelixa.com/v1/printers/8dpmm/labels/4x6/0"      --data-binary @label.zpl --output label.png

Keep the decoded bytes exactly as they are. If you requested a character set other than the default, the label bytes follow that encoding; decoding the file as UTF-8 and re-encoding it can replace or reject every accented or Turkish character, and the preview will show precisely that damage. Feed the raw bytes to the preview and, unchanged, to the printer.

Checks worth running before printing

curl -X POST "https://api.labelixa.com/v1/diagnostics?dpmm=8&w=4&h=6"      --data-binary @label.zpl

The same gate runs from a shell or CI as npx labelixa validate label.zpl, which exits non-zero on error-level findings.

Failures that look like UPS problems but are not

Frequently asked questions

How do I request a ZPL label from the UPS Shipping API?

Set LabelSpecification.LabelImageFormat.Code to ZPL and give LabelStockSize with Width 4 and Height 6 (or 8) in whole inches. The specification notes that the image only scales up to 4×6 even when 4×8 is requested.

Where is the ZPL in the UPS response?

ShipmentResponse.ShipmentResults.PackageResults[].ShippingLabel.GraphicImage, base64-encoded, one entry per package; ImageFormat.Code confirms the format. From v2403 the package results are always an array.

Does the UPS request say which dpi the ZPL is written for?

No — the specification has no resolution field. Read the density from the file with the size and DPI analyzer, then preview and print at that density.

Related guides

What is ZPL?

ZPL is the language Zebra thermal printers understand. How to read the commands, how a label is put together, and the most common mistakes.

Which barcode symbology should I use?

EAN-13, Code 128 or QR? Practical rules for picking a barcode based on your data, your space and the scanner that has to read it.

How to preview a ZPL file without a printer

A ZPL file is just text — the label only exists once something draws it. Three practical ways to see a ZPL label before it reaches the printer.

Try your own ZPL code →