ShipStream Knowledge Base

Packed and Shipped API Migration Guide (2026.7)

For integration developers. In version 2026.7, inventory leaves On Hand when a Shipment ships instead of when it is packed, and Orders complete when they ship.

API responses and webhook timing change when your instance is updated to 2026.7. Update your integration before the release.

The Change in One Table

When a Shipment is…Before the releaseAfter the release
PackedLeaves On Hand. Movement ship. Order complete.Stays On Hand, in the new qty_packed. Movement pack. Order packed (new status).
ShippedNo inventory change.Leaves On Hand. Movement ship. Order complete once every Shipment has shipped.

A Shipment becomes Shipped when its Manifest is loaded, the carrier's tracking shows it in transit, the carrier is set to mark Shipments Shipped automatically, or someone marks it Shipped. As a backstop, anything still Packed 30 days after packing is marked Shipped automatically.

Shipment and Package statuses do not change.

Green marks what is new, orange what keeps its name but changes meaning or timing, and the red dashed link is removed: a packed Shipment no longer completes its Order.

What Happens to On Hand

On Hand never goes up because of this change. It simply stops dropping at pack and drops at ship instead, so it drops a little later. Example: 100 units, 10 packed each day, picked up by the carrier 3 days later.

DayOn Hand before the releaseOn Hand after the releaseWaiting on the dock
19010010
28010020
37010030
4609030
5508030

The difference is always exactly what is waiting on the dock (qty_packed). If you compare our On Hand with a system that subtracts at pack, compare against qty_on_hand − qty_packed.

API and Webhook Changes

WhereChange
order.info, order.searchNew status packed (state processing). complete and completed_at now happen when the last Shipment ships.
Global API /v1/shipping/ordersSame as above: new status packed, and complete when the last Shipment ships. The Global API always reports the real status; the compatibility option below does not apply to it.
order.cancelA packed Order can only be canceled where canceling complete Orders is allowed. Canceling packed Shipments creates cancellation requests that the Warehouse resolves.
inventory.list, .detailed, .detailed_packaging, .lots; Global API inventory levels; Inventory SnapshotNew qty_packed, included in qty_on_hand (and in qty_held for Lots on hold). qty_picked is unchanged.
stock_movement.listNew actions pack / unpack at pack time. ship / unship now mean leaving the dock. New fields qty_packed, qty_shipped, parent_type, parent_id. location holds the Packing Station on pack rows and the Manifest Load Location on ship rows.
Webhook order:completedSent when the last Shipment ships, not at pack.
Webhook order:status_changedSent for processing → packed, then packed → complete.
Webhook shipment:packedorder_status in the payload is packed instead of complete.
Webhook order:items_updatedAlso sent with order:canceled when canceling all items leaves cancellation requests on packed Shipments.
Webhook track:createdNo longer sent when a tracking number is removed.
Shipment, Package, and other webhooksUnchanged.

Shipments that ship during packing. On an External Shipping Method set to Automatically Mark Shipped, a Shipment ships as soon as its tracking number is entered, which can happen during packing. As before, it then sends shipment:shipped but not shipment:packed. If the Order's other Shipments have already shipped, it goes straight from processing to complete and is never packed.

Temporary compatibility option. Your warehouse can report Order status packed as complete in the Merchant API and grid exports while you update your integration, and a status filter of complete then also matches packed Orders. Timing, webhooks, inventory, and the Global API are not affected. The option will be removed in version 2026.8. Administrators set it with Report Packed Orders as Complete (Legacy, Temporary) under System > Configuration > Shipping > Orders > General, globally or per Merchant; Admin UI exports use only the global value.

Partly canceled Shipments. A Shipment with part of its quantity already canceled can no longer be marked Shipped by a user or the API, because its Packages and label may no longer match its remaining items. The Warehouse voids its label and reverts it instead.

On Release Day

  • On Hand does not change. Shipments already packed have already left On Hand, and nothing is added back.
  • Orders already complete stay complete.
  • Shipments packed more than 30 days ago and never marked Shipped become Shipped with shipped_at = their packed time. No webhooks are sent for these, and the updated_at of these Shipments, their Packages, and their Orders does not change, so polling for recently updated records does not find them. Shipments with a pending or partial cancellation are left Packed.
  • Shipments packed in the last 30 days ship normally, with the usual webhooks. Their ship movement row has no quantities, because the quantity was recorded when they were packed.
  • Old movement rows are relabelled from ship to pack in the background over the following days. We will announce when that is finished.

Checklist for Your Integration

  • Order status: accept packed. If you use complete to mean "packed", use packed or the shipment:packed webhook instead, and also handle shipment:shipped for Shipments that ship during packing.
  • On Hand: decide whether you want qty_on_hand or qty_on_hand − qty_packed.
  • Movement log: pack = packed, ship = left the dock. Handle the two kinds of pack row and the three kinds of ship row shown below; unpack and unship rows are the same, in reverse.
  • Shipments you hold as Packed: after the release, re-read the Shipments your system still holds as Packed (or waiting for tracking) to pick up the ones the release marked Shipped.
  • Movement history copies: if you copy stock_movement.list incrementally, re-read rows from before the release once we announce the relabel is finished.
if (in_array($movement['entity_action'], ['pack', 'unpack'], TRUE)) {
    if (isset($movement['qty_packed'])) {
        // Packed (or unpacked) after the release: still on hand
    } else {
        // Shipment packed before the release: left On Hand at packing (or came back)
    }
} elseif (in_array($movement['entity_action'], ['ship', 'unship'], TRUE)) {
    if (isset($movement['qty_packed'])) {
        // Left the dock (or came back), packed after the release
    } elseif (isset($movement['qty_picked'])) {
        // Old row, not yet relabelled: packed and left On Hand (or came back)
    } else {
        // Left the dock (or came back), packed before the release; nothing to subtract
    }
}

Changes Since the October 3 Preview

If you received the early preview of this guide, these details were added or changed:

  • order.cancel: a packed Order can only be canceled where canceling complete Orders is allowed, and canceling packed Shipments creates cancellation requests.
  • Webhooks: order:items_updated can accompany order:canceled, and track:created is no longer sent when a tracking number is removed.
  • Shipments on an External Shipping Method set to Automatically Mark Shipped can ship during packing and are never packed.
  • Partly canceled Shipments can no longer be marked Shipped by a user or the API.
  • The compatibility option is set by your warehouse's administrators, does not apply to the Global API, and will be removed in version 2026.8.
  • Release day: Shipments the release marks Shipped keep their updated_at, and Shipments with a pending or partial cancellation stay Packed.
  • Checklist: re-read the Shipments you hold as Packed after the release, and handle pack rows recorded before the release.

Questions? Contact help@shipstream.io.