feat: add third-party order logistics APIs

This commit is contained in:
wushumin
2026-06-11 14:34:12 +08:00
parent d13db60618
commit fa267c4413
4 changed files with 496 additions and 30 deletions

View File

@@ -1,11 +1,11 @@
# 第三方订单对接文档
版本v1
更新日期2026-05-08
版本v1.1
更新日期2026-06-11
## 1. 对接说明
本文档用于第三方系统对接安心验开放接口。第三方推送订单时,只需要提供第三方自己的订单号 `external_order_no`,不需要提前传物品信息。具体物品信息会在鉴定师鉴定时由平台侧补充完善
本文档用于第三方系统对接安心验开放接口。第三方推送订单时,最小只需要提供第三方自己的订单号 `external_order_no`。如第三方已具备服务套餐、物品信息、寄回地址、鉴定资料或寄入物流,也可以在创建订单时一并传入,平台会直接落入订单资料,减少后续人工补录
接口域名以实际环境为准,本文统一使用:
@@ -113,29 +113,161 @@ function sign_request(string $method, string $pathWithQuery, string $body, strin
| `422` | 请求参数不合法 |
| `500` | 服务端处理失败 |
## 4. 创建订单
## 4. 套餐获取
第三方创建订单前,可以先调用本接口获取当前可用服务套餐和价格,再将返回的 `price_package_code` 传入创建订单接口。
```text
GET /api/open/v1/service-price-packages
```
### 4.1 查询参数
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `service_provider` | string | 否 | 服务方,可选 `anxinyan``zhongjian`;不传返回全部服务方启用套餐 |
### 4.2 cURL 示例
```bash
curl -X GET 'https://{api-domain}/api/open/v1/service-price-packages?service_provider=anxinyan' \
-H 'Content-Type: application/json' \
-H 'X-AXY-App-Key: your_app_key' \
-H 'X-AXY-Timestamp: 1715155200' \
-H 'X-AXY-Nonce: random_nonce' \
-H 'X-AXY-Signature: calculated_signature'
```
GET 请求参与签名的 `raw_body` 为空字符串,`path_with_query` 需要包含实际查询字符串。
### 4.3 成功响应示例
```json
{
"code": 0,
"message": "ok",
"data": {
"service_providers": [
{
"service_provider": "anxinyan",
"service_provider_text": "安心验鉴定",
"sla_hours": 48,
"default_price_package_code": "anxinyan_basic",
"packages": [
{
"service_provider": "anxinyan",
"service_provider_text": "安心验鉴定",
"price_package_name": "安心验基础套餐",
"price_package_code": "anxinyan_basic",
"price_package_price": 99,
"description": "默认服务价格套餐",
"is_default": true,
"sla_hours": 48
}
]
}
]
}
}
```
### 4.4 响应说明
- 接口只返回启用套餐,不返回停用套餐。
- `price_package_code` 可直接作为创建订单接口的 `price_package_code` 参数。
- `default_price_package_code` 表示该服务方当前默认套餐;创建订单不传 `price_package_code` 时,平台会使用当前服务方默认启用套餐。
## 5. 创建订单
```text
POST /api/open/v1/orders
```
第三方创建订单时只需要传 `external_order_no`。平台会创建一笔待收货订单,后续物品信息由鉴定师在鉴定工作台补充
第三方创建订单时,最小只需要传 `external_order_no`。平台会创建一笔待寄送商品订单;如请求中包含套餐、物品、地址、资料或寄入物流,平台会同步写入订单主表、商品资料、寄回地址、初始鉴定资料和寄入物流记录
### 4.1 请求参数
### 5.1 请求参数
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `external_order_no` | string | 是 | 第三方订单号。同一对接客户下必须唯一 |
| `service_provider` | string | 否 | 服务方,可选 `anxinyan``zhongjian`,默认 `anxinyan` |
| `product_info` | object | 否 | 物品信息,当前可不传 |
| `materials` | array | 否 | 鉴定资料图片 URL 列表,当前可不传 |
| `return_address` | object | 否 | 退回地址,当前可不传;如传任一地址字段,则必填完整地址 |
| `inbound_logistics` | object | 否 | 寄入物流信息,当前可不传 |
| `price_package_code` | string | 否 | 服务价格套餐编码,可通过套餐获取接口取得;不传时使用当前服务方的默认启用套餐;传入无效或已停用编码时返回 `422` |
| `product_info` | object | 否 | 物品信息。不传时订单会保留待完善物品信息 |
| `materials` | array | 否 | 鉴定资料图片 URL 列表或资料对象列表。不传时不会生成初始资料文件 |
| `return_address` | object | 否 | 寄回地址。不传时后续由平台或用户补充;如传任一地址字段,则必填完整地址 |
| `inbound_logistics` | object | 否 | 寄入物流信息。不传时后续可由入库台按订单号、鉴定单号或外部订单号匹配入库 |
| `express_company` | string | 否 | 寄入快递公司,可替代 `inbound_logistics.express_company` |
| `tracking_no` | string | 否 | 寄入运单号,可替代 `inbound_logistics.tracking_no` |
| `extra_info` | object | 否 | 扩展信息,当前可不传 |
| `extra_info` | object | 否 | 购买、成色、附件、备注等扩展信息 |
### 4.2 最小请求示例
### 5.2 可选对象字段
`product_info` 支持:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `category_id` | integer | 否 | 平台品类 ID。第三方无法确定 ID 时可不传 |
| `category_name` | string | 否 | 品类名称 |
| `brand_id` | integer | 否 | 平台品牌 ID。第三方无法确定 ID 时可不传 |
| `brand_name` | string | 否 | 品牌名称 |
| `product_name` | string | 否 | 商品名称;不传时平台会尝试用品牌和品类拼接展示 |
| `color` | string | 否 | 颜色 |
| `size_spec` | string | 否 | 规格或尺寸 |
| `serial_no` | string | 否 | 序列号、刻印号或其他唯一标识 |
`return_address` 支持:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `consignee` | string | 条件必填 | 收件人 |
| `mobile` | string | 条件必填 | 手机号 |
| `province` | string | 条件必填 | 省份 |
| `city` | string | 条件必填 | 城市 |
| `district` | string | 条件必填 | 区县 |
| `detail_address` | string | 条件必填 | 详细地址 |
只要 `return_address` 中任意字段有值,上述字段都必须完整填写。
`materials` 支持两种格式:
```json
[
"https://example.com/item-front.jpg",
{
"item_code": "front",
"item_name": "商品正面图",
"file_url": "https://example.com/item-front.jpg",
"thumbnail_url": "https://example.com/item-front-thumb.jpg",
"is_required": true
}
]
```
资料文件当前只支持 `http``https` 图片 URL。对象格式中 `file_url``url` 等价;`thumbnail_url` 不传时默认使用原图 URL。
`extra_info` 支持:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `purchase_channel` | string | 否 | 购买渠道 |
| `purchase_price` | number | 否 | 购买价格 |
| `purchase_date` | string | 否 | 购买日期,建议格式 `YYYY-MM-DD` |
| `usage_status` | string | 否 | 使用状态 |
| `condition_desc` | string | 否 | 成色描述 |
| `has_accessories` | boolean | 否 | 是否有附件 |
| `accessories` | array | 否 | 附件列表 |
| `remark` | string | 否 | 备注 |
`inbound_logistics` 支持:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `express_company` | string | 成对填写 | 寄入快递公司 |
| `tracking_no` | string | 成对填写 | 寄入运单号 |
如果希望创建订单时同步写入寄入物流,需要同时提供快递公司和运单号。也可以直接使用顶层 `express_company``tracking_no`,含义与 `inbound_logistics` 内字段一致。
### 5.3 最小请求示例
```json
{
@@ -143,12 +275,21 @@ POST /api/open/v1/orders
}
```
### 4.3 带可选字段请求示例
### 5.4 带可选字段请求示例
```json
{
"external_order_no": "THIRD202605080002",
"service_provider": "anxinyan",
"price_package_code": "anxinyan_basic",
"product_info": {
"category_name": "箱包",
"brand_name": "CHANEL",
"product_name": "Classic Flap 手袋",
"color": "黑色",
"size_spec": "中号",
"serial_no": "A12345678"
},
"inbound_logistics": {
"express_company": "顺丰速运",
"tracking_no": "SF1234567890"
@@ -160,11 +301,30 @@ POST /api/open/v1/orders
"city": "杭州市",
"district": "西湖区",
"detail_address": "文三路 1 号"
},
"materials": [
{
"item_code": "front",
"item_name": "商品正面图",
"file_url": "https://example.com/materials/front.jpg",
"thumbnail_url": "https://example.com/materials/front-thumb.jpg",
"is_required": true
}
],
"extra_info": {
"purchase_channel": "专柜",
"purchase_price": 68000,
"purchase_date": "2026-06-01",
"usage_status": "轻微使用",
"condition_desc": "外观轻微使用痕迹",
"has_accessories": true,
"accessories": ["防尘袋", "盒子"],
"remark": "第三方同步订单"
}
}
```
### 4.4 cURL 示例
### 5.5 cURL 示例
```bash
curl -X POST 'https://{api-domain}/api/open/v1/orders' \
@@ -176,7 +336,7 @@ curl -X POST 'https://{api-domain}/api/open/v1/orders' \
-d '{"external_order_no":"THIRD202605080001"}'
```
### 4.5 成功响应示例
### 5.6 成功响应示例
```json
{
@@ -194,6 +354,9 @@ curl -X POST 'https://{api-domain}/api/open/v1/orders' \
"order_status": "pending_shipping",
"display_status": "待寄送商品",
"payment_status": "paid",
"price_package_name": "安心验基础套餐",
"price_package_code": "anxinyan_basic",
"price_package_price": 99,
"pay_amount": 99,
"estimated_finish_time": "2026-05-09 12:00:00",
"created_at": "2026-05-08 12:00:00",
@@ -219,21 +382,22 @@ curl -X POST 'https://{api-domain}/api/open/v1/orders' \
}
```
### 4.6 幂等规则
### 5.7 幂等规则
同一个对接客户下,`external_order_no` 作为幂等键:
- 第一次请求会创建订单。
- 后续使用相同 `external_order_no` 且请求内容一致时,不会重复创建订单,会返回已有订单,`data.idempotent``true`
- 后续使用相同 `external_order_no` 但请求内容不一致时,返回 `409`
- 如第一次只传最小字段,后续不能再用同一个 `external_order_no` 重推补充字段;如需补充资料,应走平台补录、入库或补料流程。
建议第三方重试创建订单时保持请求 JSON 内容一致,仅重新生成 `timestamp``nonce``signature`
## 5. 查询订单
## 6. 查询订单
支持按第三方订单号或平台订单号查询订单进度。
### 5.1 按第三方订单号查询
### 6.1 按第三方订单号查询
```text
GET /api/open/v1/orders/{external_order_no}
@@ -250,14 +414,14 @@ curl -X GET 'https://{api-domain}/api/open/v1/orders/THIRD202605080001' \
-H 'X-AXY-Signature: calculated_signature'
```
### 5.2 通过查询参数查询
### 6.2 通过查询参数查询
```text
GET /api/open/v1/orders?external_order_no=THIRD202605080001
GET /api/open/v1/orders?order_no=AXY20260508120000123
```
### 5.3 响应示例
### 6.3 响应示例
```json
{
@@ -274,6 +438,9 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
"order_status": "report_published",
"display_status": "报告已发布",
"payment_status": "paid",
"price_package_name": "安心验基础套餐",
"price_package_code": "anxinyan_basic",
"price_package_price": 99,
"pay_amount": 99,
"estimated_finish_time": "2026-05-09 12:00:00",
"created_at": "2026-05-08 12:00:00",
@@ -300,13 +467,81 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
}
```
## 6. 订单状态
## 7. 发货通知
第三方在商品实际寄出后,可以调用本接口通知平台写入寄入物流。创建订单接口中的 `inbound_logistics` 仍然可用;但如果订单创建和商品寄出不是同一时点,建议创建订单时只建单,实际寄出后再调用本接口提交快递信息。
```text
POST /api/open/v1/orders/shipping
```
### 7.1 请求参数
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `external_order_no` | string | 是 | 第三方订单号。只能提交当前 `app_key` 所属客户下的订单 |
| `express_company` | string | 是 | 寄入快递公司 |
| `tracking_no` | string | 是 | 寄入运单号 |
### 7.2 请求示例
```json
{
"external_order_no": "THIRD202606110001",
"express_company": "顺丰速运",
"tracking_no": "SF1234567890"
}
```
### 7.3 成功响应示例
```json
{
"code": 0,
"message": "运单已提交",
"data": {
"idempotent": false,
"updated": false,
"logistics": {
"express_company": "顺丰速运",
"tracking_no": "SF1234567890",
"tracking_status": "submitted",
"latest_desc": "客户已提交寄送运单:顺丰速运 SF1234567890等待鉴定中心签收。",
"latest_time": "2026-06-11 12:00:00"
},
"order": {
"customer_id": "CUST001",
"customer_code": "CUST001",
"external_order_no": "THIRD202606110001",
"order_no": "AXY20260611120000123",
"order_status": "pending_shipping",
"display_status": "已提交运单",
"inbound_logistics": {
"express_company": "顺丰速运",
"tracking_no": "SF1234567890",
"tracking_status": "submitted",
"latest_desc": "客户已提交寄送运单:顺丰速运 SF1234567890等待鉴定中心签收。",
"latest_time": "2026-06-11 12:00:00"
}
}
}
}
```
### 7.4 重复提交规则
- 相同 `external_order_no``express_company``tracking_no` 重复提交时,接口返回成功,`idempotent``true`,不会重复写物流节点或订单时间线。
- 同一订单在 `pending_shipping` 状态下提交不同快递公司或运单号时,会更新最新一条寄入物流,`updated``true`,并追加“已更新运单”时间线。
-`pending_shipping` 状态的订单不允许提交或更新寄入运单,返回 `422`
- 找不到当前客户下的 `external_order_no` 时返回 `404`
## 8. 订单状态
常见订单状态如下,最终以接口返回的 `order_status``display_status` 为准。
| order_status | display_status | 说明 |
| --- | --- | --- |
| `pending_shipping` | 待寄送商品 | 订单已创建,等待物品到仓或人工确认收货 |
| `pending_shipping` | 待寄送商品 / 已提交运单 | 订单已创建,等待物品到仓或人工确认收货 |
| `received` | 鉴定中心已收货 | 物品已到仓 |
| `appraising` | 物品鉴定中 | 鉴定师正在鉴定 |
| `generating_report` | 物品鉴定完成 | 鉴定完成,报告生成中 |
@@ -315,7 +550,7 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
| `completed` | 已完成 | 订单完成 |
| `pending_supplement` | 需要补充资料 | 需要补充资料 |
## 7. Webhook 事件回调
## 9. Webhook 事件回调
如需接收订单状态变化通知,第三方需向平台提供可公网访问的 `webhook_url`,并由平台开启回调。
@@ -336,7 +571,7 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
| 总超时 | 6 秒 |
| 成功判定 | HTTP 状态码为 2xx 且无网络错误 |
### 7.1 回调报文
### 9.1 回调报文
```json
{
@@ -355,7 +590,7 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
}
```
### 7.2 事件类型
### 9.2 事件类型
| event_code | event_text | status_code | status_text |
| --- | --- | --- | --- |
@@ -368,7 +603,7 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
| `completed` | 订单已完成 | `completed` | 已完成 |
| `supplement_required` | 需要补充资料 | `pending_supplement` | 需要补充资料 |
### 7.3 回调接收建议
### 9.3 回调接收建议
第三方接收 webhook 时建议:
@@ -376,10 +611,12 @@ GET /api/open/v1/orders?order_no=AXY20260508120000123
- 收到事件后返回 HTTP 2xx。
- 如需强一致的最新状态,可以收到 webhook 后再调用订单查询接口确认。
## 8. 对接流程建议
## 10. 对接流程建议
1. 平台分配 `app_key``app_secret`
2. 第三方完成签名调试。
3. 第三方调用创建订单接口,只传 `external_order_no` 即可
4. 第三方可通过查询接口主动查询订单状态
5. 如启用 webhook平台在订单状态变化时主动通知第三方。
3. 第三方调用套餐获取接口,确认可用套餐和 `price_package_code`
4. 第三方调用创建订单接口。最小只传 `external_order_no` 即可;如需要减少后续人工补录,建议同步传 `price_package_code``product_info``return_address``materials``inbound_logistics`
5. 商品实际寄出后,第三方调用发货通知接口提交 `express_company``tracking_no`
6. 第三方可通过查询接口主动查询订单状态。
7. 如启用 webhook平台在订单状态变化时主动通知第三方。