Skip to content

Orders, Shipments, and Labels

How orders, shipments, rates, and labels relate, and which commands move each one along.

Updated September 3, 20262 min readPostsale CLI

In Postsale, fulfilling work spans three related objects: orders, shipments, and labels. An order does not contain its label, and shipments are found through their parent orders. This article maps the domain the way the CLI uses it.

In this article, we will define orders, shipments, and labels, explain how they join, show how to list shipments from the CLI, and point you to work queue and empty-search behavior.

Before We Begin

This article assumes that:

  • You have at least one order in the account (imported or manual)
  • postsale account env shows your environment and API host

What each object is

ObjectRole
OrderCommerce record: buyer, ship-to, line items, status, tags. Status names are defined by your account, not a global enum.
ShipmentCarrier-facing package plan for an order: packages, service, rates, tracking state.
LabelThe purchased shipping document for a shipment. Void is a separate money-moving path. Reprint is not a purchase.

How they connect

A shipment's reference field holds the parent order id when the shipment is created. That join is the backbone of CLI workflows.

text
Order  ──creates/owns──►  Shipment(s)  ──purchase──►  Label
 id                         reference = order id

Note

User-set fields like reference_1 / reference_2 / reference_3 on a shipment are different from this join reference.

Orders do not embed full shipments

You can filter orders with shipment-related conditions, but the order payload still does not carry complete shipment records. After you know order ids, fetch shipments explicitly.

How to get shipments from the CLI

There is no separate "shipment search universe" independent of orders. Supported paths:

  1. postsale shipments list
    Finds orders (natural language --query, structured JSON, or a default of orders that already have shipments), loads their shipments, and prints shipment-level rows with order_id and order_number. Pagination is at order grain. This command is CLI composition (not in schema --list).

  2. postsale shipments get --reference <order_id>
    All shipments for one order.

  3. postsale shipments get [shipment_id]
    One shipment by id (the id is optional when you pass --reference <order_id> instead).

  4. Agent tools
    search_orders then list_shipments_for_orders, or get_shipment.

A subtle backend detail

Shipments-by-order lookups are classified as read, but the backend may write during some of them: for unprocessed US shipments missing address validation, it can validate and save the address. They stay safe to call; the CLI just suppresses automatic retry on those paths.

Labels: purchase, void, reprint

ActionRiskCLI
PurchaseMoney-movingpostsale labels purchase ... --yes / agent purchase_labels
VoidMoney-movingpostsale labels void ... --yes / agent void_shipment
ReprintReadpostsale labels reprint <shipment_id> (optional --output to download)

Reprint re-fetches an existing label PDF URL. It does not charge again. Refunds after void depend on the carrier and backend state. The CLI does not guarantee a refund.

Finding work without silent empties

"What should I ship?" is a product question. In the agent, prefer get_work_queue over guessing status strings. Wrong statuses return zero orders that look like success.

When agent search returns zero matches, read _cli_meta.empty_result_context before concluding the account is empty. Full detail: Search and the work queue.

Try it

Here's how:

  1. Search recent orders:
bash
postsale orders search --query "orders from last 7 days" --page-size 10
  1. List shipments for a similar window:
bash
postsale shipments list --query "orders from last 7 days" --page-size 10
  1. Load every shipment for one order:
bash
postsale shipments get --reference <order_id>
  1. If a label already exists and you only need the PDF again:
bash
postsale labels reprint <shipment_id>

Success looks like JSON rows you can identify by order and shipment ids, without purchasing anything new.

Good to Know

  • Web app shipping help (Dock, rate selector, void in the UI) is on postsale.com/help. The CLI paths above are the terminal equivalents for the same domain objects.
  • Rate quotes can apply temporary dimension estimates. Do not reuse those estimates for real purchases. See Intent builders.
  • Creating a shipment and purchasing a label are separate money-moving steps in the agent tool model.
  • PUT updates of shipments, orders, and origin addresses are full replacements. A field you leave out is cleared, so read the object first and send it back whole. Carrier accounts are the exception in the CLI: carriers update reads the current account and merges your keys onto it before calling the API (which itself replaces the whole record), so pass the id and only what you are changing (see carriers).
  • Bulk shipment updates touch only unprocessed shipments, skip the rest silently, and return no body. Re-read the shipments to confirm what changed.
  • A processed USPS shipment carries sender_address and return_address: the label addresses copied from the USPS carrier account's settings at purchase time. Set them with postsale carriers update (see carriers).
  • A shipment with test_label: true produces watermarked, never-billed carrier test labels (USPS and UPS only). Store automation still runs for it. See Shipping, labels, and rates. POSTSALE_TEST_LABEL_MODE makes the CLI stamp the flag on every shipment it creates and refuse to buy labels for any shipment without it — see the safety model.
  • Order fields a store's retention policy has redacted read as the literal string [REDACTED]; the order's redacted block says which and why.

Additional Reading