← All field notes
Reliability

Idempotency is how you prevent duplicate shipping labels

Retries are inevitable. Duplicate labels are not. Here is how to design the request key, server boundary, and station ledger around physical output.

Every production worker retries. A connection closes after a request body is sent. A process restarts before committing its own state. A queue redelivers a message because an acknowledgement arrived late.

For database updates, a duplicate attempt may be annoying. For printing, it creates another physical object. Two valid shipping labels for one order can become two parcels, a mis-ship, or a long warehouse investigation.

The goal is not to eliminate retries. The goal is to make the same instruction safe to repeat.

Start with a business identity

An idempotency key should describe the unique print your business intends, not the network attempt used to send it.

Good keys are deterministic:

order-1042-shipping-label
return-882-rma-label
shipment-993-packing-slip-v2

A fresh UUID created inside every retry defeats the mechanism because each attempt looks new. Generate the key when the business event is created and retain it beside the event.

Include a version only when the intended document has genuinely changed. Reprinting the same label after a timeout should use the same key. Printing a corrected label with a changed address should use a new, intentional identity.

The API protects the creation boundary

Send the key with the print-job request:

POST /api/v1/print-jobs
X-API-Key: rp_live_...
Idempotency-Key: order-1042-shipping-label
Content-Type: application/json

On the first valid request, RocketPrint creates a job and returns its ID. If the identical request arrives again under the same key, the API returns the original job rather than inserting a new one. The Idempotency-Replayed response header makes that behavior visible.

If the same key arrives with different input, RocketPrint returns a conflict. It does not silently accept the second payload and it does not pretend two different labels are the same instruction.

That conflict is a design signal. Either the caller accidentally reused an identity or the business document changed and needs an explicit new version.

Why an API-only check is not enough

Duplicate creation is one failure mode. Duplicate delivery is another.

Imagine this sequence:

  1. RocketPrint sends job A to a station.
  2. The station prints it.
  3. The station process stops before its completion message reaches the API.
  4. The connection returns and job A is delivered again during recovery.

The API still has one record, but a stateless station could print that record twice.

RocketPrint Station therefore keeps a durable local ledger of jobs it has claimed and their outcomes. When a known job is delivered again after a restart or reconnect, the station replays the recorded outcome instead of issuing another local print command.

These two boundaries solve different problems:

Boundary Protects against
API idempotency key A caller retry creating a second job
Station ledger A known job being delivered to the station again

Neither boundary should be removed because the other exists.

Do not call it exactly once

“Exactly once” is attractive language and a poor description of physical systems.

There is always an interval where the print command may have succeeded and the reporting process may have failed. A computer can record that it intends to print before sending bytes, or record that it printed after the command returns, but a crash can happen between those actions.

RocketPrint makes two narrower, testable promises:

  • replaying the same API instruction does not create a second job;
  • redelivering a job already recorded by the station does not intentionally issue a second print.

Those are meaningful duplicate-prevention guarantees. They are not proof that one readable label—and only one—physically emerged in every possible hardware failure.

Design the worker transaction

A robust order worker keeps its own relationship between the business event and the RocketPrint job:

shipment_id
document_purpose
document_version
idempotency_key
rocketprint_job_id
last_observed_status

Before creating work, check whether the business event already has a RocketPrint job ID. If not, submit with the stored idempotency key. If the request outcome is unknown, repeat the same request and key. Store the returned job ID, whether the response represents the first creation or a replay.

Then poll that job to a terminal state. Do not create another job merely because polling was delayed.

Decide what a manual reprint means

A human pressing “reprint” is different from an automatic retry. It is an intentional request for another physical label and should create a new business identity, record who requested it, and explain why.

For example:

order-1042-shipping-label-reprint-1

That makes the audit trail honest. The automatic system can prove it did not duplicate a job, while the operations team can still produce a replacement when stock was damaged or lost.

Test the ugly path

Before launch, test more than the happy response:

  • send the exact request twice and confirm the job ID is unchanged;
  • reuse the key with different content and confirm the conflict;
  • stop a caller after it sends the request but before it stores the response, then retry;
  • restart the station around delivery and confirm a known job is not intentionally printed again;
  • exercise the manual-reprint path and confirm it has a distinct identity.

Retries are infrastructure behavior. Duplicate labels are business behavior. A good integration separates them explicitly.

Read the full RocketPrint reliability model or start with the five-minute label quickstart.

END / idempotency-prevents-duplicate-shipping-labels

More field notes