Skip to content

Couple Zimarkers for high-speed or offline printing

High-speed label printing needs coupling that keeps up. This guide uses a bank of pre-allocated Zimarkers plus asynchronous coupling so nothing blocks the printing process:

  1. A background process keeps a local bank of Zimarkers full, so codes are always available on-site.
  2. When a label is printed, you couple its code to a pallet with a fire-and-forget async call, either right away or from an offline queue that drains when connected.
  3. A webhook reports back afterwards, so you only act on the couplings that failed.

For the concepts behind banks, allocation, and sync vs. async, see the Coupling API overview.

Prerequisites

Step 1: Keep the bank filled (background)

Run this in a background process, not in the print loop, typically a small Node.js, Python, or .NET service triggered by a cron job. Allocate a batch of Zimarkers ahead of time and store them locally. Each allocated code comes with its printable image, so once they're banked you can print without any live call.

POST /integration/rest/api/v1/zmarker-code/allocate?quantity=50

curl -X POST "https://api.zimark.link/integration/rest/api/v1/zmarker-code/allocate?quantity=50" \
  -H "X-AUTH-KEY: ZIM.your-api-key-here"

The batch is reserved atomically: all-or-nothing. 200 OK returns a list of allocated codes:

[
  { "markerCode": "68", "markerImage": "iVBORw0KGgoAAA…" },
  { "markerCode": "69", "markerImage": "iVBORw0KGgoAAA…" }
]
  • markerCode: the Zimarker code, reserved for you and never reused.
  • markerImage: the marker as a base64-encoded PNG, ready to print. (Add ?imageDelivery=URL to get a markerImageUrl instead.)

The filler itself is a small loop: check how many unused codes are left locally, and if that count is below a threshold, allocate a batch to refill. Run it on a timer or trigger it whenever the bank drops below a low-water mark. Size the batch so it comfortably covers what you print between checks, and the bank never runs dry mid-run.

Two things keep it reliable:

  • Allocation is all-or-nothing. A failed batch allocates nothing, so treat a 400 as "refill later" and retry. Never assume a partial batch.
  • Allocated codes are consumed immediately. From Zimark's side a code is spent the moment it's allocated, so your local store is the source of truth for what's still unused. Persist it durably. Codes lost from the bank can't be reclaimed.

Step 2: Couple at print time (asynchronous)

When you print a label, take the next code from your local bank and couple it to the pallet's WMS ID. Use async=true: the call validates up front, returns immediately with an operation identifier, and finishes coupling in the background. Your printer never waits.

POST /integration/rest/api/v1/track/couple?async=true

curl -X POST "https://api.zimark.link/integration/rest/api/v1/track/couple?async=true" \
  -H "X-AUTH-KEY: ZIM.your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "markerCode": "68",
    "wmsId": "LPN00012345"
  }'

Request fields

FieldTypeRequiredNotes
markerCodestringYesThe Zimarker code from your bank.
wmsIdstringYesThe pallet's WMS ID.
customFieldsarrayNo{ fieldKey, fieldValue } pairs to set on the pallet.

202 Accepted returns an operation identifier. Coupling then completes in the background:

{
  "operationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Because the response comes back before coupling finishes, print the label and move on. The 202 means the request was accepted and validated, not that coupling succeeded. That outcome arrives on the webhook.

Step 3: Reconcile failures via webhook

Every async coupling reports its outcome on the coupling-events webhook: COUPLING_SUCCEEDED or COUPLING_FAILED. Since you fire and forget, this is where you catch the ones that didn't take: a duplicate WMS ID, an already-coupled marker, or a validation error. Match the event back to your request by operationId.

The exact payload isn't part of the OpenAPI spec yet; the shape below is illustrative. Confirm the field names against a live delivery before relying on them.

{
  "category": "COUPLING",
  "eventIdentifier": "evt-9f3c…",
  "triggerName": "COUPLING_FAILED",
  "triggerTime": 1783164318353,
  "payload": {
    "operationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "markerCode": "68",
    "wmsId": "LPN00012345",
    "reason": "DUPLICATE_WMS_ID"
  }
}

Handle it like any other Zimark webhook. See Webhook Reference for the envelope and idempotency rules. In practice:

  • COUPLING_SUCCEEDED: nothing to do; the pallet is coupled.
  • COUPLING_FAILED: the label is printed but not linked. Re-couple: draw a fresh code from the bank and call POST /track/couple again for that wmsId, or flag the pallet for manual handling.

Confirm it worked

  • Step 1 returned a batch of codes now sitting in your local bank.
  • Step 2 returned 202 with an operationId for each label, and printing didn't wait.
  • Your webhook receives one COUPLING_SUCCEEDED or COUPLING_FAILED per operation, and failures are re-coupled.

If a call fails synchronously, check Troubleshooting. A 400 on allocation means the batch exceeds the maximum size or there isn't enough produced inventory; a 400 on couple means the code is invalid, already coupled, or the WMS ID is a duplicate.