← All field notes
Agentic Commerce

When an AI agent places the order, who prints the label?

Agentic commerce protocols are changing how orders arrive, not what happens after. The parcel still needs a pick, a pack, and a label, and that label path now needs identity, expiry, and a record an agent can read.

An agent can negotiate a cart, choose a shipping option, and pay. It cannot pick the item off a shelf, put it in a box, or stick a label on it. Everything downstream of the order is unchanged, which means agentic commerce arrives at your warehouse as a change in traffic shape and a change in who is asking questions, not as a new fulfillment technology.

That has consequences for the least glamorous part of the pipeline, the step that turns an order into a piece of paper on a box. This post is about what to change there.

Agentic commerce rewrites the checkout, not the parcel

The Agentic Commerce Protocol is an open specification for letting a buyer's agent complete a purchase with a merchant. Its repository lists OpenAI, Stripe, and Meta as lead maintainers. Stripe documents the implementation side in its agentic commerce docs.

The spec has moved quickly. Versions are dated, and each one has a changelog entry in the repository.

Version What it added
2025-09-29 Initial release: agentic checkout and delegate payment
2025-12-12 Breaking changes from early adapter implementations, including fulfillment_address becoming fulfillment_details
2026-01-16 Open authentication provider model for 3DS, plus a required merchant_id on PaymentProvider
2026-01-30 Capability negotiation, a payment handlers framework, and an extensions framework
2026-04-17 Feed API, cart capability, delegate authentication, an MCP transport binding, and mandatory idempotency requirements

Two details in that table are worth pausing on. The 2026-04-17 release makes idempotency a stated requirement of the protocol rather than a suggestion, which tells you the spec authors hit the same problem this post is about. And the payment piece is a Shared Payment Token: Stripe's documentation describes it as a scoped grant issued to a specific seller's Stripe profile, carrying usage limits for currency, maximum amount, and expiry, and deactivated once it is consumed, expired, or revoked. A credential bound to one recipient, one amount, and one window is the right instinct, and it is worth stealing for your own internal instructions, a point this post returns to.

There is a cost side. One write-up reports the Instant Checkout fee at 4%. We have not confirmed that figure with a primary source, so treat it as something to verify with your own payment provider.

Separately, the Model Context Protocol, introduced by Anthropic in November 2024 and under Linux Foundation governance since December 2025, is how agents get tools at all. The New Stack's roadmap piece covers the state of it. The 2026-04-17 ACP release adds an MCP transport binding, so agent tooling and commerce plumbing are now specified against each other.

None of this says anything about the label. That is the point.

Four things that change behind the order

Orders arrive in bursts. A human checkout flow is rate-limited by human attention. Agent flows are not, and a retailer's agent integration going live looks, from the warehouse's perspective, like an unannounced flash sale.

Retries come from machines. An agent that does not get a clean response retries on its own schedule, with its own backoff, and without the instinct a person has that pressing the button twice might be bad.

There is less human review before an order exists. The traditional funnel had a person who noticed that the address looked wrong or the quantity was 300 instead of 3. That check moves later, which usually means it moves to the person at the pack bench holding a label.

The questions get asked by software. "Where is my order" from an agent is a request for structured status, repeated on a timer, and it wants more than a boolean.

Bursts are a rate-limit problem before they are a printer problem

Printers are slow in a way that is invisible until it is not. Whatever your label printer's throughput is, it is fixed, and it is fine for 500 orders spread across a day and a bottleneck at 500 orders in ten minutes. Measure it once on your own hardware, because that number is the ceiling of your burst handling.

So plan the burst at the queue, not at the device. Accept the orders, enqueue the label jobs, and let the printer drain at its own pace. Do not treat a slow printer as a failure to be retried, because a retry storm against a busy printer is how you get a pile of duplicates on the floor.

Know your API's limit behavior too. RocketPrint is a remote printing API and desktop Station for software platforms: your backend POSTs a print job, and a small app beside the printer prints it, with no inbound networking, no drivers for raw label formats, and a durable job record. It applies rate limits per API key and returns 429 with a Retry-After header, which is a number to honor rather than a reason to spin.

Agent retries are not human retries, so key idempotency on the order

If there is one change to make before agent traffic reaches you, this is it: derive the label's identity from the business object, not from the attempt.

An agent-driven order flow multiplies the number of places a retry can originate. The agent retries the order call. Your order service retries the fulfillment call. Your worker retries the print call. Any of those can produce a second label for one parcel unless the identity is stable across all of them.

// The key describes the label you intend, not the attempt that sends it.
const idempotencyKey = `order-${order.id}-shipping-label`;

const res = await fetch("https://rocketprint.io/api/v1/print-jobs", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.ROCKETPRINT_API_KEY,
    "Idempotency-Key": idempotencyKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    printerId: packBench.printerId,
    contentType: "raw_base64",
    content: Buffer.from(zpl).toString("base64"),
    title: `Shipping label for order ${order.id}`,
    expiresInSeconds: 1800,
  }),
});

// A replay returns the original job and sets Idempotency-Replayed.
const replayed = res.headers.get("Idempotency-Replayed") !== null;

Two behaviors make that key useful. An identical request under the same key returns the original job with an Idempotency-Replayed response header, so a retry is cheap and visible. A different payload under the same key returns 409, which is the system telling you that something upstream changed the label without changing its identity. That 409 is worth alerting on in an agent-fed pipeline, because it usually means an agent revised an order after you generated a document from it.

The general case is covered in how idempotency prevents duplicate shipping labels.

Stale labels need an expiry, because the pick window is the real deadline

An agent can cancel or modify an order seconds after placing it. If a label was already queued for a printer that is offline, and the printer comes back two hours later, it prints a label for an order that no longer exists.

Give every label job a deadline that matches the operational window rather than the technical default. Print jobs accept expiresInSeconds from 10 to 86,400, defaulting to 3,600, and a job that is not dispatched by its deadline becomes expired. For a pack bench where labels are applied within the shift, something like 1,800 seconds is more honest than an hour.

Also know your cancel window. A job can be canceled while it is still pending. Once it has been sent to the machine beside the printer, cancellation is not available, and the recovery is a human voiding a label rather than an API call. Design the order-change flow around that boundary instead of assuming a late cancel will win.

Answer an agent with a record, not with "done"

An agent asking about an order does not benefit from "shipped: true". It benefits from states it can reason about, and so does the human reading the transcript afterwards.

Expose the label's state, the timestamps, and the failure reason if there is one. Our own status list is deliberately narrow about what it proves: completed means the print command succeeded through the OS print path, not that paper emerged and not that the barcode scans. The full list is in what remote print job statuses actually mean, and it exists because "done" is not a fact anybody can act on.

For reconciliation, GET /v1/print-jobs returns jobs newest first and filters by status and printer, which is how you answer "what did this pack bench print during the burst" after the fact. Endpoints and options are in the API reference.

What we do not offer for this, plainly

We do not ship webhooks. If you want to push label status back toward an order system or an agent-facing endpoint, you poll, or you use the Node client's waitFor helper. For a burst of agent orders that is more polling than anyone enjoys, and the gap is ours.

We do not publish an MCP server. If you want an agent to trigger a print directly, you build that tool over the REST API yourself. That is not a bad outcome: a tool you write is a tool you can constrain, which is the argument in Anthropic's guidance on writing tools for agents, including the advice to say in the tool description when not to use it. We wrote up the design we would use in giving an AI agent a printer.

And print content is deleted seven days after a job reaches a terminal state. The job record with status, timestamps, and failure reason is kept, but if your dispute process needs the label image itself after a week, store it on your side.

The label path checklist for agent-placed orders

  • Derive the idempotency key from the order, and store it next to the order.
  • Alert on 409 conflicts. In an agent pipeline they mean the document changed underneath a stable identity.
  • Set expiresInSeconds from the operational window, not the default.
  • Queue and drain rather than retrying against a saturated printer, and honor Retry-After.
  • Return states and timestamps to anything that asks, not a boolean.
  • Keep your own copy of anything a dispute might need.
  • Decide, in writing, what happens when an order is canceled after the label was sent.

None of that is agent-specific engineering. It is the same discipline that survives a Black Friday queue backlog or a flaky order worker. Agent traffic just removes the delay between you getting it wrong and finding out.

If you want to see the label path end to end before deciding any of this, the quickstart prints a ZPL label with two curl commands.

END / ai-agent-orders-who-prints-the-label

More field notes