TMS 运单开放接口-批量下单
基本信息
- 方法:
POST - 路径:
/label/sync-batch-create
用途
接收一次批量下单请求,落库批次与明细,并异步执行。每条明细处理完成以及整批完成时,会向 callbackUrl 发起 POST 回调通知。单条成功回调的 labels 字段与 /label/create 同步返回的 data 完全一致。
公共请求头
所有 TMS 运单开放接口都需要传以下请求头:
Content-Type: application/json
Apikey: {{api_key}}
Apisign: {{api_sign}}
Timestamp: {{timestamp}}
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| callbackUrl | string | 是 | 回调地址,必须为带 scheme 与 host 的合法 URL,生产环境仅允许 https |
| items | array | 是 | 批量下单明细列表,至少 1 条,上限由系统配置决定(默认 500) |
items 字段
每条元素内嵌运单结构,下表只列出非嵌入字段。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| itemReference | string | 是 | 明细外部唯一标识;同一批次内不允许重复 |
| apiUserCode | string | 是 | 该明细对应的客户编号;缺失会被预校验拒绝(apiUserCode is required) |
| serviceCode | string | 是 | 该明细使用的服务代码;缺失会被预校验拒绝(serviceCode is required) |
| accountId | uint | 否 | 指定账号 ID,与运单创建接口一致 |
| shipFrom | object | 是 | 发件地址,结构同运单创建接口 |
| shipTo | object | 是 | 收件地址,结构 同运单创建接口 |
| packages | array | 是 | 包裹列表,结构同运单创建接口 |
| products | array | 否 | 商品列表,结构同运单创建接口 |
| options | object | 否 | 附加选项,结构同运单创建接口 |
| sellerOrderNumber | string | 否 | 卖家订单号 |
请求示例
{
"callbackUrl": "https://client.example.com/tms/batch-callback",
"items": [
{
"itemReference": "ITEM-001",
"apiUserCode": "CUST-001",
"serviceCode": "UPARCEL_GROUND",
"accountId": 0,
"shipFrom": {
"name": "Sender Company",
"countryCode": "US",
"stateCode": "CA",
"city": "Los Angeles",
"addressLine1": "123 Main St",
"postalCode": "90001",
"phone": "1234567890",
"isResidential": false
},
"shipTo": {
"name": "Receiver Company",
"countryCode": "US",
"stateCode": "NY",
"city": "New York",
"addressLine1": "456 Madison Ave",
"postalCode": "10001",
"phone": "1234567890",
"isResidential": false
},
"packages": [
{
"length": 10,
"width": 8,
"height": 6,
"weight": 5.5,
"quantity": 1,
"declaredValue": 120
}
],
"options": {
"shipDate": "2026-06-26",
"dimensionUnitCode": "IN",
"weightUnitCode": "LBS",
"declaredValueCurrencyCode": "USD"
},
"sellerOrderNumber": "SO-20260626-001"
},
{
"itemReference": "ITEM-002",
"apiUserCode": "CUST-001",
"serviceCode": "FEDEX_GROUND",
"shipFrom": {
"name": "Sender Company",
"countryCode": "US",
"stateCode": "CA",
"city": "Los Angeles",
"addressLine1": "123 Main St",
"postalCode": "90001",
"isResidential": false
},
"shipTo": {
"name": "Receiver Company",
"countryCode": "US",
"stateCode": "TX",
"city": "Houston",
"addressLine1": "9100 Southwest Freeway",
"postalCode": "77036",
"isResidential": false
},
"packages": [
{
"length": 12,
"width": 10,
"height": 8,
"weight": 7.5,
"quantity": 1
}
]
}
]
}
成功响应示例
{
"code": 200,
"data": {
"batchId": 42,
"batchNo": "async_c8f3k2abc",
"totalCount": 2,
"acceptedCount": 2,
"rejectedCount": 0,
"status": "processing"
},
"message": "success"
}
提交 3 条、其中 1 条缺 serviceCode 时(部分受理):
{
"code": 200,
"data": {
"batchId": 43,
"batchNo": "async_abc123",
"totalCount": 3,
"acceptedCount": 2,
"rejectedCount": 1,
"status": "processing"
},
"message": "success"
}
返回字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| data.batchId | uint | 批次主键 ID |
| data.batchNo | string | 批次编号,格式 async_{xid} |
| data.totalCount | int | 提交 item 总数 |
| data.acceptedCount | int | 受理通过、进入异步队列的数量 |
| data.rejectedCount | int | 受理阶段拒绝的数量(如缺 serviceCode/apiUserCode) |
| data.status | string | 批次当前状态,见下方 |
批次状态
| 取值 | 含义 |
|---|---|
pending | 初始状态,通常不会出现于受理响应 |
processing | 存在 accepted item,异步处理中 |
partial_success | 全部 accepted item 已终态,存在失败 |
success | 全部 accepted item 创建成功 |
failed | 全部 accepted item 失败,或整批无 accepted item |
明细状态
| 取值 | 含义 |
|---|---|
rejected | 受理阶段同步校验未通过 |
pending | 已受理,等待异步执行 |
processing | 异步执行中 |
success | 创建成功 |
failed | 异步创建失败 |
回调通知
回调由系统侧主动发起,POST 到请求里的 callbackUrl,Content-Type: application/json。
- 每条回调 body 均含
callbackType字段(item= 单条明细回调 /batch= 批次完成回调),调用方可据此快速分流 - 回调失败自动重试,回调任务最多重试 3 次
- 回调失败不影响订单业务终态
- 回调地址仅允许
https(SSRF 防护:拒绝私网 / 环回 / 保留地址) - 调用方应返回 HTTP 2xx,否则 TMS 按重试策略重新投递
回调签名验证
每条回调请求(单条回调与批次回调)均携带签名头,算法与入站接口签名完全一致,调用方使用同一个 AppSecret 即可验证:
| Header | 类型 | 说明 |
|---|---|---|
| Apikey | string | 与调用 /label/sync-batch-create 时相同的 API Key |
| Apisign | string | 签名值 |
| Timestamp | string | 秒级 Unix 时间戳(参与签名,建议校验 ±120 秒窗口防重放) |
签名算法:
Apisign = 大写( MD5( AppSecret + Timestamp ) )
验证伪代码:
expected = upper_case(md5(app_secret + request.header("Timestamp")))
if request.header("Apisign") == expected
and abs(now() - request.header("Timestamp")) <= 120:
# 验签通过
若 TMS 侧查不到该用户的签名密钥(数据异常),回调仍会发出但不带签名头。调用方可按自身安全策略选择放行或拒绝无签名回调。
明细级回调(每条处理完成时)
每条明细到达终态时推送,包括受理阶段 rejected 与异步执行 success / failed。
{
"callbackType": "item",
"batchId": 42,
"batchNo": "async_c8f3k2abc",
"itemId": 123,
"itemReference": "ORDER-001",
"status": "success",
"shipmentNumber": "SH20260611001",
"trackingCode": "1Z999AA10123456784",
"labels": {
"masterTrackingNumber": "1Z999AA10123456784",
"shipmentOrderNumber": "SH20260611001",
"carrierCode": "UPS",
"serviceCode": "UPS_GROUND",
"totalCharge": 12.5,
"currencyCode": "USD",
"chargeItems": [
{ "code": "BASE", "value": 10.5, "currencyCode": "USD" },
{ "code": "FUEL", "value": 2.0, "currencyCode": "USD" }
],
"labelUrl": "https://tms.example.com/file/label/shipment_abc123",
"labelFileType": "pdf",
"trackingNumbers": ["1Z999AA10123456784"],
"shipmentLabels": [
{
"carrierCode": "UPS",
"serviceCode": "UPS_GROUND",
"trackingNumber": "1Z999AA10123456784",
"rate": 12.5,
"labelUrl": "https://tms.example.com/file/label/shipment_abc123/1Z999AA10123456784",
"labelFileType": "pdf",
"labelData": "",
"labelDataType": "pdf",
"labelType": "LabelUrl",
"createdAt": "2026-06-11 10:00:00",
"statusCode": ""
}
],
"labels": [
{ "trackingCode": "1Z999AA10123456784", "labelUrl": "https://tms.example.com/file/label/shipment_abc123/1Z999AA10123456784", "fileType": "pdf" }
],
"sellerOrderNumber": "SO-001",
"createLabelTime": "2026-06-11 10:00:00"
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
| callbackType | string | 固定 item,单条明细回调 |
| batchId | uint | 批次 ID |
| batchNo | string | 批次编号,async_{xid} |
| itemId | uint | 批次明细 ID |
| itemReference | string | 明细外部标识 |
| status | string | 明细终态:rejected / success / failed |
| shipmentNumber | string | 运单号(成功时有值) |
| trackingCode | string | 主追踪号(成功时有值) |
| errorCode | string | 失败错误码(failed 时有值,其余省略) |
| errorMessage | string | 失败/拒绝原因(成功时省略) |
| labels | object | 与 /label/create 同步返回的 data 完全一致(ShipmentResults 结构,面单为 labelUrl 下载地址而非 base64 文件),仅 status=success 时存在 |
labels 字段说明(与 /label/create 的 data 相同):
| 字段 | 类型 | 说明 |
|---|---|---|
| masterTrackingNumber | string | 主跟踪号 |
| shipmentOrderNumber | string | 运单号 |
| freightShipmentId | string | 货运批次号(部分渠道) |
| carrierCode | string | 承运商代码 |
| serviceCode | string | 渠道服务编码 |
| totalCharge | float | 总费用 |
| currencyCode | string | 币种 |
| chargeItems | array | 费项明细 [{code,value,currencyCode}] |
| labelUrl | string | 面单下载 URL |
| labelFileType | string | 面单文件类型 |
| trackingNumbers | array | 跟踪号列表 |
| shipmentLabels | array | 面单明细(labelData 已在服务端保存为文件并清空,实际返回 labelUrl) |
| labels | array | 面单索引 [{trackingCode,labelUrl,fileType}] |
| sellerOrderNumber | string | 销售单号 |
| createLabelTime | string | 出单时间 |
rejected 示例:
{
"callbackType": "item",
"batchId": 43,
"batchNo": "async_abc123",
"itemId": 456,
"itemReference": "ORDER-003",
"status": "rejected",
"shipmentNumber": "",
"trackingCode": "",
"errorMessage": "serviceCode is required"
}
failed 示例:
{
"callbackType": "item",
"batchId": 43,
"batchNo": "async_abc123",
"itemId": 457,
"itemReference": "ORDER-004",
"status": "failed",
"shipmentNumber": "",
"trackingCode": "",
"errorCode": "carrier_error",
"errorMessage": "UPS: rating service unavailable"
}
批次级回调(整批处理完成时)
触发时机:
- 所有 accepted item 均已到达终态(
success/failed) - 或整批无 accepted item(全部 rejected)时,受理后立即触发
{
"callbackType": "batch",
"batchId": 42,
"batchNo": "async_c8f3k2abc",
"totalCount": 2,
"acceptedCount": 2,
"rejectedCount": 0,
"successCount": 1,
"failedCount": 1,
"status": "partial_success"
}
| 字段 | 类型 | 说明 |
|---|---|---|
| callbackType | string | 固定 batch,批次完成回调 |
| batchId | uint | 批次 ID |
| batchNo | string | 批次编号 |
| totalCount | int | 提交总数 |
| acceptedCount | int | 受理通过数 |
| rejectedCount | int | 受理拒绝数 |
| successCount | int | 异步创建成功数 |
| failedCount | int | 异步创建失败数 |
| status | string | 批次终态(success / failed / partial_success) |