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.
The Change in One Table
| When a Shipment is… | Before the release | After the release |
|---|---|---|
| Packed | Leaves On Hand. Movement ship. Order complete. | Stays On Hand, in the new qty_packed. Movement pack. Order packed (new status). |
| Shipped | No 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.
| Day | On Hand before the release | On Hand after the release | Waiting on the dock |
|---|---|---|---|
| 1 | 90 | 100 | 10 |
| 2 | 80 | 100 | 20 |
| 3 | 70 | 100 | 30 |
| 4 | 60 | 90 | 30 |
| 5 | 50 | 80 | 30 |
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
| Where | Change |
|---|---|
order.info, order.search | New status packed (state processing). complete and completed_at now happen when the last Shipment ships. |
Global API /v1/shipping/orders | Same 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.cancel | A 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 Snapshot | New qty_packed, included in qty_on_hand (and in qty_held for Lots on hold). qty_picked is unchanged. |
stock_movement.list | New 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:completed | Sent when the last Shipment ships, not at pack. |
Webhook order:status_changed | Sent for processing → packed, then packed → complete. |
Webhook shipment:packed | order_status in the payload is packed instead of complete. |
Webhook order:items_updated | Also sent with order:canceled when canceling all items leaves cancellation requests on packed Shipments. |
Webhook track:created | No longer sent when a tracking number is removed. |
| Shipment, Package, and other webhooks | Unchanged. |
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
completestaycomplete. - 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 theupdated_atof 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
shipmovement row has no quantities, because the quantity was recorded when they were packed. - Old movement rows are relabelled from
shiptopackin the background over the following days. We will announce when that is finished.
Checklist for Your Integration
- Order status: accept
packed. If you usecompleteto mean "packed", usepackedor theshipment:packedwebhook instead, and also handleshipment:shippedfor Shipments that ship during packing. - On Hand: decide whether you want
qty_on_handorqty_on_hand − qty_packed. - Movement log:
pack= packed,ship= left the dock. Handle the two kinds ofpackrow and the three kinds ofshiprow shown below;unpackandunshiprows 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.listincrementally, 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: apackedOrder can only be canceled where cancelingcompleteOrders is allowed, and canceling packed Shipments creates cancellation requests.- Webhooks:
order:items_updatedcan accompanyorder:canceled, andtrack:createdis 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
packrows recorded before the release.
Questions? Contact help@shipstream.io.