Shipments and states
EasyPick tracks the shipment status and the physical compartment state separately. A webhook is an event announcing a change; it does not necessarily change the shipment status itself.
Shipment status
Section titled “Shipment status”reserved -> loaded -> picked_up | | +----------+-> cancelled / expired / fault| Status | Meaning |
|---|---|
reserved |
A compartment is reserved, but loading has not been confirmed. |
loaded |
The shipment is inside. Also inspect pickup_enabled. |
picked_up |
Customer pickup is confirmed. The compartment may still be in cooldown. |
cancelled |
The shipment was cancelled. If it was already loaded, the compartment awaits physical removal. |
expired |
The reservation or pickup deadline expired. Loaded contents must be physically removed. |
fault |
Terminal shipment status after an operation that could not be completed safely. |
cancelled, expired, and fault are terminal statuses. Physically removing the contents does not move them to another shipment status.
Physical compartment state
Section titled “Physical compartment state”Public GET /shipments/{shipment_id} responses and webhook payloads include compartment_state.
compartment_state |
Meaning |
|---|---|
reserved |
The compartment is assigned to the shipment, but loading has not been confirmed. |
occupied |
The compartment physically contains the shipment. |
awaiting_removal |
The shipment is terminal, but an operator must physically remove the contents. |
cooldown |
Pickup is confirmed, but the compartment is waiting for operational release. |
available |
The compartment is actually free and can be reserved for another shipment. |
shipment creation: available -> reservedloading: reserved -> occupiedempty reservation: reserved --door_available--> availableterminal after loading: occupied -> awaiting_removalphysical removal: awaiting_removal --removed + door_available--> availablepickup: occupied -> cooldown --door_available--> availableThe removed event confirms physical removal from a compartment in awaiting_removal. The following door_available event confirms its actual release. Neither event changes the terminal shipment status.
Loading protection
Section titled “Loading protection”After first loading, the status immediately becomes loaded, but pickup_enabled remains false during the protection period. The loader can reopen the compartment with the same PIN to correct its contents. Notify the customer only after receiving the loaded webhook: EasyPick delays it until the protection period has ended and the door is confirmed closed.
Create
Section titled “Create”POST /shipmentsContent-Type: application/jsonAuthorization: Bearer {api_key}
{ "box_id": "box_01k3example", "external_order_id": "ORDER-2026-1042", "customer_name": "Jane Smith", "reservation_ttl_minutes": 1440, "pickup_ttl_minutes": 4320}TTL fields are optional. The selected box settings apply when they are omitted.
Read status
Section titled “Read status”GET /shipments/{shipment_id}The response includes compartment_state in addition to status. Do not use the shipment status as the only signal that the compartment can be assigned again. The status endpoint does not return the PIN. Use GET /shipments/{shipment_id}/pickup-pin for an audited reveal.
Cancel
Section titled “Cancel”POST /shipments/{shipment_id}/cancelA reserved or loaded shipment can be cancelled. Repeating a cancellation is idempotent.
- An empty reservation immediately moves to
compartment_state=available, and EasyPick emitsdoor_available. - A loaded shipment moves to
status=cancelled, but the compartment remains incompartment_state=awaiting_removal. An operator must physically remove its contents; onlyremovedfollowed bydoor_availableconfirms release.
Recovery after fault
Section titled “Recovery after fault”fault is a terminal shipment status, not an automatic compartment release. The standard safe recovery flow is:
- The operator selects open for removal.
- The box confirms the
closed -> open -> closedsensor cycle. - The operator confirms that the compartment is empty.
- EasyPick emits
removedfollowed bydoor_available; the shipment remainsfault, while the compartment moves toavailable.
Use emergency release only after physically checking that the compartment is empty. Skipping this check can cause the system to assign a compartment that still contains goods.
Retry after a fault
Section titled “Retry after a fault”POST /shipments/{shipment_id}/retryAuthorization: Bearer {api_key}This endpoint is available only for a shipment in fault whose original compartment has actually been released (compartment_state=available). It creates a new attempt with the same external_order_id, reserves a currently available compartment, and generates a new PIN. The original shipment remains in fault for audit purposes.
The operation is idempotent with respect to the original faulted shipment ID. Repeated calls return the same new attempt and the same new PIN; they do not create additional reservations.
The original POST /shipments remains idempotent to its first request: repeating it with the same external_order_id returns the first attempt. Always use /retry after a fault and persist the returned replacement shipment ID.
When a compartment is reusable
Section titled “When a compartment is reusable”The only public state confirming that another reservation is possible is compartment_state=available. The door_available webhook is the canonical event after every actual compartment release:
- after the normal post-pickup cooldown,
- after
removedfor a loaded shipment incancelled,expired, orfault, - after immediately releasing a reservation that was never loaded.
door_available does not change the shipment status.