Integration

Printing ZPL from S3 or Azure Blob - and archiving printed labels there

Object storage is where print files already live: carrier labels from the shipping provider, pre-rendered batches from the ERP, archives kept for retention r…

Object storage is where print files already live: carrier labels from the shipping provider, pre-rendered batches from the ERP, archives kept for retention rules. This guide covers both directions - printing ZPL out of a bucket, and writing printed ZPL back into one.

Everything applies to Amazon S3 and Azure Blob Storage. Because the S3 interface is standardised, MinIO, Cloudflare R2, Wasabi, Backblaze B2 and Ceph work as well.

Creating a storage connection

Under Streaming → Storage → New connection you create the connection once. The name matters: it is how messages address the connection later.

FieldS3Azure Blob
Bucket / containerbucket namecontainer name
Regione.g. eu-central-1not used
Endpointempty for AWS, otherwise e.g. https://minio.example.comnot used
Path styleswitch on for MinIO and Cephnot used
Prefixoptional, e.g. zpl/optional
CredentialsAccessKey=…;SecretKey=…connection string or container SAS URL

The credentials are stored AES-encrypted in the platform database. They never travel back to the browser - the form only shows that credentials exist. With S3 you may leave them out entirely: the normal AWS credential chain then applies, for instance the environment's IAM role.

Test verifies that the bucket and the permissions are right before anything is printed.

Direction 1: printing ZPL from the bucket

A bus message can carry finished ZPL. For large files that is awkward - many brokers cap the message size, and a label with an embedded graphic gets big quickly. Better: the message only points at it.

{
  "schemaVersion": 1,
  "printer": "rp:7",
  "zplRef": { "storage": "archive", "key": "orders/4711.zpl" }
}

storage is the name of your connection, key the object key inside it. A configured prefix is prepended: with the prefix zpl/ the example above reads zpl/orders/4711.zpl.

The file is fetched at print time, not on receipt. The name resolves within your own or your company's scope only - someone else's connection cannot be reached through a message, even by somebody who knows its name.

Direction 2: storing the printed ZPL and reporting it

The reverse direction is called an output target. It bundles three steps that run after a successful print, and each one is switched on separately:

1. Store - the printed ZPL is written as a file into a storage connection.

2. Notify - a message goes to a bus, any of the seven.

3. Trigger - an HTTP POST to your own URL, HMAC-SHA256 signed.

The file name comes from a template. All times are UTC:

Template: {yyyy}/{MM}/{dd}/{subscription}/{id}.zpl
Result:   2026/09/09/Outbound/8f3c1e2a9b7d4c0e.zpl

Available are {yyyy} {MM} {dd} {HH} {mm} {ss}, {subscription}, {printer}, {key} (the key of the bus message) and {id} for a unique id per label.

The notification and the webhook receive the same payload:

{
  "schemaVersion": 1,
  "event": "label.printed",
  "utc": "2026-09-09T12:34:56.7890000Z",
  "subscription": "Outbound",
  "printer": "rp:7",
  "storageKey": "zpl/2026/09/09/Outbound/8f3c1e2a.zpl",
  "storageUrl": "https://archive.s3.eu-central-1.amazonaws.com/zpl/2026/09/09/...",
  "zplBytes": 812,
  "zpl": null
}

The ZPL itself is only included if you explicitly ask for it. Otherwise the field is null and the URL is enough - which keeps the message small.

What this is good for

  • Retention rules. Shipping labels are records. An archive in your own bucket, under your provider's lifecycle rules, satisfies that without a second system.
  • Reprints without re-rendering. Whatever was printed once exists byte for byte. A reprint is the same file, not a new render.
  • Handover to downstream systems. The webhook tells the ERP that carton 12 has been labelled, and hands over the link to the record at the same time.

A storage failure never stops the print

Storing, notifying and the webhook all run after the print. If the bucket is briefly unreachable, the label is printed regardless; the error lands as text in the subscription log. An archive should not hold up operations.

An output target can be exercised at any time with Test: it stores a sample ZPL and fires the notification and the webhook without printing anything.