Shipments
Create, pay, cancel, intercept, list, and fetch international outbound shipments (/v1/fulfillment/shipments/*).
Lifecycle {#lifecycle}
Public status codes: PENDING → WAIT_PAYMENT → WAIT_SHIP → SHIPPED → SIGNED. Cancel → CANCELLED.
Create / pay still return a summary total (freight / services / discount / payment). List is lightweight; detail is the full view (split boxes, packing media, first/last-mile relabel, charge lines, warehouse timeline). Scan events stay on International tracking. Field reference: response models.
Retired: POST /v1/fulfillment/shipments/preview, POST /v1/fulfillment/shipments/logistics/trace, POST /v1/fulfillment/shipments/cancel, POST /v1/fulfillment/shipments/detail. Use {id}/tracking, {id}/cancel, and GET {id} instead. Exact freight is returned on create.
POST /v1/fulfillment/shipments/create {#create}
Required: tracking_numbers[], receiver, shipping_channel_code. Optional:
external_shipment_id— idempotency keyremark
total.payment is the amount charged on pay:
"total": {
"freight": { "amount": 8900, "currency": "CNY" },
"services": { "amount": 1500, "currency": "CNY" },
"discount": { "amount": 200, "currency": "CNY" },
"payment": { "amount": 10200, "currency": "CNY" }
}Returns id, order_sn, and status (typically PENDING). Public id is the warehouse numeric PK as a string (e.g. "115"); order_sn is the warehouse order number (e.g. JIYUNRI1349). Subsequent pay / cancel / detail / tracking paths use this id.
Create errors (live warehouse → 4xx error object):
| HTTP | error.code | Warehouse upstream_code | Typical message |
|---|---|---|---|
| 404 | PARCEL_NOT_FOUND | SHIPMENT_PACKAGE_NOT_FOUND | 部分包裹不存在 |
| 400 | SHIPMENT_CREATE_EXCEPTION | SHIPMENT_CREATE_EXCEPTION | 请先更新包裹…物品属性信息 / 有包裹不是已入库,下单失败 |
| 400 | SHIPMENT_CREATE_FAILED | SHIPMENT_CREATE_FAILED | 创建订单失败 |
| 409 | EXTERNAL_ORDER_ID_ALREADY_EXISTS | EXTERNAL_ORDER_ID_ALREADY_EXISTS | 外部订单号已存在 |
POST /v1/fulfillment/shipments/{shipment_id}/pay {#pay}
POST /v1/fulfillment/shipments/115/pay
Authorization: Bearer <API_KEY>Path {shipment_id} is create/detail id (live warehouse numeric PK as a string, e.g. "115"). Warehouse also accepts order_sn. Sandbox uses sbs_* / sb_shp_*. Body may be empty. Warehouse upstream: POST /api/gateway-worker/v1/shipments/pay with { "shipment_id" } only — not external_shipment_id.
Charges fulfillment wallet. Successful pay → WAIT_SHIP.
Pay errors:
| HTTP | error.code | Warehouse upstream_code | Typical message |
|---|---|---|---|
| 404 | NOT_FOUND | SHIPMENT_NOT_EXISTS | 订单不存在 |
| 409 | SHIPMENT_NOT_READY_FOR_PAYMENT | SHIPMENT_NOT_READY_FOR_PAYMENT | 该批货物尚未达到可结算状态… |
| 409 | SHIPMENT_ALREADY_PAID | SHIPMENT_ALREADY_PAID | 订单已支付 |
| 402 | INSUFFICIENT_BALANCE | INSUFFICIENT_BALANCE | 余额不足 |
Sandbox sb_shp_pay_insufficient may still return 200 + success: false + error_code. Live warehouse uses the 4xx error object. See Errors.
POST /v1/fulfillment/shipments/{shipment_id}/cancel {#cancel}
cancel_reason is required. Warehouse upstream: POST /api/gateway-worker/v1/shipments/cancel with { shipment_id, cancel_reason }.
{
"cancel_reason": "buyer_request"
}Cancellable while PENDING or WAIT_PAYMENT. Success → CANCELLED.
POST /v1/fulfillment/shipments/{shipment_id}/intercept {#intercept}
v1 requests a hold after outbound has started. This does not change shipment lifecycle status. Warehouse upstream: POST /api/gateway-worker/v1/shipments/set-exceptional with { shipment_id, reason, remark }.
{
"reason": "CUSTOMER_REQUEST",
"remark": "Customer requested to stop the shipment before dispatch."
}reason is a fixed CODE: CUSTOMER_REQUEST / ADDRESS_ISSUE / ORDER_CHANGE / PAYMENT_ISSUE / COMPLIANCE_ISSUE / PACKAGE_ISSUE / OTHER. remark is required when reason is OTHER.
Success:
{
"shipment_id": "107",
"interception": {
"status": "REQUESTED",
"reason": "ADDRESS_ISSUE",
"remark": "Customer address needs to be corrected.",
"requested_at": "2026-08-20T12:30:00Z"
}
}interception.status: REQUESTED → PROCESSING → INTERCEPTED / FAILED. Detail can show status: "SHIPPED" with interception.status: "REQUESTED".
Mock allows WAIT_SHIP and SHIPPED. PENDING / WAIT_PAYMENT / SIGNED / CANCELLED → SHIPMENT_NOT_INTERCEPTABLE. Use cancel before outbound.
| HTTP | error.code |
|---|---|
| 404 | SHIPMENT_NOT_FOUND |
| 409 | SHIPMENT_NOT_INTERCEPTABLE |
| 409 | SHIPMENT_INTERCEPTION_ALREADY_REQUESTED |
| 422 | INVALID_INTERCEPTION_REASON |
| 422 | INTERCEPTION_REMARK_REQUIRED |
Sandbox: sb_shp_shipped can request intercept; sb_shp_unpaid / sb_shp_signed cannot; sb_shp_intercepted is already INTERCEPTED. Live warehouse SHIPMENT_NOT_EXISTS maps to SHIPMENT_NOT_FOUND.
GET /v1/fulfillment/shipments {#list}
GET /v1/fulfillment/shipments?status=WAIT_SHIP&created_from=2026-08-01&page=1&page_size=20
Authorization: Bearer <API_KEY>Lightweight rows. Split boxes, packing files, legs, charge lines, timeline, and interception stay on detail. Warehouse upstream: POST /api/gateway-worker/v1/shipments/index.
| Query | Notes |
|---|---|
status | Comma-separated or repeated. PENDING / WAIT_PAYMENT / WAIT_SHIP / SHIPPED / SIGNED / CANCELLED |
created_from | Lower bound (YYYY-MM-DD or datetime) |
created_to | Upper bound |
page | Default 1 |
page_size | Default 20, max 100 |
Each row has id (warehouse numeric PK as a string), order_sn, external_shipment_id, status, international_tracking, receiver, shipping_channel, services, total, payment_status, and times. Empty warehouse strings become null. Amounts are fen.
International tracking lives only on international_tracking — there is no top-level tracking_number. List times omit updated_at / packing_started_at (those stay on detail).
Sandbox includes fixtures (sb_shp_unpaid, sb_shp_shipped, sb_shp_signed, sb_shp_intercepted, …) plus dynamic sbs_* from create.
{
"data": [
{
"id": "107",
"order_sn": "JIYUNRI1338",
"status": "WAIT_SHIP",
"external_shipment_id": "MY-INTL-ORDER-001",
"international_tracking": {
"tracking_number": null,
"carrier": null
},
"receiver": {
"name": "John Doe",
"mobile": "+12025550123",
"email": "john@example.com",
"country_code": "US",
"province": "California",
"city": "Los Angeles",
"district": null,
"postal_code": "90001",
"address_line1": "123 Main St",
"address_line2": "Apt 4B"
},
"shipping_channel": {
"code": "PUHUO",
"name": "General Cargo Air Line"
},
"services": [
{
"id": "2",
"service_code": "2",
"name": "Package Reinforcement",
"quantity": 1,
"status": "PENDING"
}
],
"total": {
"charges": {
"amount": 2000,
"currency": "CNY"
},
"discount": {
"amount": 0,
"currency": "CNY"
},
"payable": {
"amount": 2000,
"currency": "CNY"
},
"paid": {
"amount": 0,
"currency": "CNY"
},
"outstanding": {
"amount": 2000,
"currency": "CNY"
}
},
"payment_status": "UNPAID",
"times": {
"created_at": "2026-08-20T09:41:36Z",
"packed_at": "2026-08-20T10:20:00Z",
"paid_at": null,
"shipped_at": null,
"delivered_at": null,
"cancelled_at": null
}
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total": 1,
"total_pages": 1
},
"monetary_unit": "CNY_minor",
"request_id": "req_xxx"
}GET /v1/fulfillment/shipments/{shipment_id} {#detail}
GET /v1/fulfillment/shipments/107?language=en
Authorization: Bearer <API_KEY>Path {shipment_id} is detail id (live: warehouse numeric PK as a string, e.g. "107"; sandbox: sbs_* / sb_shp_*). Optional language is for display names (shipping_channel.name, services[].name, charges[].name). Do not expect status_name.
Warehouse upstream: POST /api/gateway-worker/v1/shipments/detail with { "shipment_id" } only. Public id is the warehouse numeric PK as a string (e.g. "107"); order_sn is the warehouse order number.
This shape covers warehouse facts create/pay cannot express:
| Problem | Where to look |
|---|---|
| Split outbound cartons | boxes[]; multi_box: true when more than one carton |
| International tracking number | international_tracking; per carton boxes[].tracking |
| Warehouse business events | timeline[] (created / packed / paid). Not scan events |
| Packing photos / video | files[]: PACKING_IMAGE / PACKING_VIDEO |
| Relabel (first mile ≠ last mile) | shipping_legs[] when the warehouse sends first/last-mile numbers |
| Block | Meaning |
|---|---|
source_packages | Inbound domestic packages before consolidation (pkg_* + China tracking number) |
boxes | Packed outbound cartons; empty [] until packed |
international_tracking | Shipment-level last-mile { tracking_number, carrier }; both null before outbound |
timeline | Warehouse business events. code may be null if warehouse sends "" |
shipping_legs | Line-haul vs destination last mile after relabel; [] until numbers exist |
files | Packing media (not inbound VAS photos on the package) |
charges | Line items. Discount rows are negative |
total | charges / discount (positive) / payable / paid / outstanding |
payment_status | UNPAID / PAID / PARTIAL |
times | Timestamps; unused nodes are null |
interception | Intercept handling, or null. Independent of shipment status |
Amounts are fen (monetary_unit: CNY_minor). Empty arrays are [], not omitted.
Sandbox: GET /v1/fulfillment/shipments/sb_shp_shipped includes split boxes, both legs, and packing files. After create → pay, a dynamic sbs_* detail is WAIT_SHIP with source_packages filled and boxes still empty.
{
"id": "107",
"order_sn": "JIYUNRI1338",
"status": "SHIPPED",
"external_shipment_id": "MY-INTL-ORDER-001",
"source_packages": [
{
"id": "pkg_01K2ABC001",
"tracking_number": "SF2026082001"
},
{
"id": "pkg_01K2ABC002",
"tracking_number": "YT2026082002"
}
],
"receiver": {
"name": "John Doe",
"mobile": "+12025550123",
"email": "john@example.com",
"country_code": "US",
"province": "California",
"city": "Los Angeles",
"district": null,
"postal_code": "90001",
"address_line1": "123 Main St",
"address_line2": "Apt 4B"
},
"shipping_channel": {
"code": "PUHUO",
"name": "General Cargo Air Line"
},
"multi_box": true,
"international_tracking": {
"tracking_number": "1Z999999999",
"carrier": "UPS"
},
"timeline": [
{
"code": "CREATED",
"title": "Shipment created",
"occurred_at": "2026-08-20T09:41:36Z"
},
{
"code": "PACKED",
"title": "Packed",
"occurred_at": "2026-08-20T10:20:00Z"
},
{
"code": "PAID",
"title": "Paid",
"occurred_at": "2026-08-20T10:30:00Z"
}
],
"boxes": [
{
"id": "box_01K2BOX001",
"box_no": "JIYUNRI1338-1",
"status": "SHIPPED",
"source_package_ids": [
"pkg_01K2ABC001",
"pkg_01K2ABC002"
],
"weight": {
"value": 4.25,
"unit": "kg"
},
"dimensions": {
"length": 45,
"width": 35,
"height": 30,
"unit": "cm"
},
"chargeable_weight": {
"value": 4.73,
"unit": "kg"
},
"tracking": {
"tracking_number": "1Z999999001",
"carrier": "UPS"
}
}
],
"shipping_legs": [
{
"type": "FIRST_MILE",
"carrier": "HioBuy Linehaul",
"tracking_number": "HB202608200001",
"origin_country": "CN",
"destination_country": "US",
"status": "DELIVERED",
"shipped_at": "2026-08-20T12:00:00Z",
"delivered_at": "2026-08-22T04:30:00Z"
},
{
"type": "LAST_MILE",
"carrier": "UPS",
"tracking_number": "1Z999999999",
"origin_country": "US",
"destination_country": "US",
"status": "IN_TRANSIT",
"shipped_at": "2026-08-22T08:00:00Z",
"delivered_at": null
}
],
"files": [
{
"id": "file_01K2ABC001",
"type": "PACKING_IMAGE",
"url": "https://cdn.hiobuy.com/shipments/JIYUNRI1338/packing-01.jpg",
"created_at": "2026-08-20T10:20:00Z"
}
],
"charges": [
{
"type": "FREIGHT",
"code": "FREIGHT",
"name": "Shipping Fee",
"amount": {
"amount": 3200,
"currency": "CNY"
}
},
{
"type": "COUPON_DISCOUNT",
"code": "COUPON",
"name": "Coupon Discount",
"amount": {
"amount": -300,
"currency": "CNY"
}
}
],
"total": {
"charges": {
"amount": 3200,
"currency": "CNY"
},
"discount": {
"amount": 300,
"currency": "CNY"
},
"payable": {
"amount": 2900,
"currency": "CNY"
},
"paid": {
"amount": 2900,
"currency": "CNY"
},
"outstanding": {
"amount": 0,
"currency": "CNY"
}
},
"payment_status": "PAID",
"times": {
"created_at": "2026-08-20T09:41:36Z",
"updated_at": "2026-08-22T08:10:00Z",
"packing_started_at": "2026-08-20T10:00:00Z",
"packed_at": "2026-08-20T10:20:00Z",
"paid_at": "2026-08-20T10:30:00Z",
"shipped_at": "2026-08-20T12:00:00Z",
"delivered_at": null,
"cancelled_at": null
},
"interception": null,
"monetary_unit": "CNY_minor",
"request_id": "req_xxx"
}See response models for charge type values.
Get Support
Need integration help? Contact Developer Support at support@hiobuy.com · Response within 1–2 business days