first
This commit is contained in:
5
docs/api/api-list.md
Normal file
5
docs/api/api-list.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# API List
|
||||
|
||||
## 第三方开放接口
|
||||
|
||||
- [第三方订单对接文档](./third-party-openapi.md):客户推送订单、订单查询、签名鉴权、Webhook 回调说明。
|
||||
385
docs/api/third-party-openapi.md
Normal file
385
docs/api/third-party-openapi.md
Normal file
@@ -0,0 +1,385 @@
|
||||
# 第三方订单对接文档
|
||||
|
||||
版本:v1
|
||||
更新日期:2026-05-08
|
||||
|
||||
## 1. 对接说明
|
||||
|
||||
本文档用于第三方系统对接安心验开放接口。第三方推送订单时,只需要提供第三方自己的订单号 `external_order_no`,不需要提前传物品信息。具体物品信息会在鉴定师鉴定时由平台侧补充完善。
|
||||
|
||||
接口域名以实际环境为准,本文统一使用:
|
||||
|
||||
```text
|
||||
https://{api-domain}
|
||||
```
|
||||
|
||||
## 2. 凭证与安全
|
||||
|
||||
平台会为每个对接方分配:
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --- | --- |
|
||||
| `app_key` | 调用方身份标识 |
|
||||
| `app_secret` | 签名密钥,请妥善保管,不要传给前端或泄露到日志中 |
|
||||
|
||||
所有开放接口都需要签名。请求必须使用 HTTPS,并携带以下请求头:
|
||||
|
||||
| Header | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `Content-Type` | 是 | 固定为 `application/json` |
|
||||
| `X-AXY-App-Key` | 是 | 平台分配的 `app_key` |
|
||||
| `X-AXY-Timestamp` | 是 | Unix 秒级时间戳,有效期 300 秒 |
|
||||
| `X-AXY-Nonce` | 是 | 随机字符串,同一个 `app_key` 下不可重复使用 |
|
||||
| `X-AXY-Signature` | 是 | 请求签名 |
|
||||
|
||||
### 2.1 签名算法
|
||||
|
||||
签名使用 HMAC-SHA256,小写十六进制输出。
|
||||
|
||||
```text
|
||||
body_hash = sha256(raw_body)
|
||||
base = UPPERCASE_HTTP_METHOD + path_with_query + timestamp + nonce + body_hash
|
||||
signature = hex_hmac_sha256(base, app_secret)
|
||||
```
|
||||
|
||||
字段说明:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `raw_body` | 原始请求体字符串。GET 请求没有请求体时为空字符串 |
|
||||
| `path_with_query` | 请求路径加查询字符串,例如 `/api/open/v1/orders?external_order_no=T202605080001` |
|
||||
| `timestamp` | 与 `X-AXY-Timestamp` 完全一致 |
|
||||
| `nonce` | 与 `X-AXY-Nonce` 完全一致 |
|
||||
|
||||
注意事项:
|
||||
|
||||
- `path_with_query` 必须与实际请求完全一致,包括查询参数顺序和 URL 编码。
|
||||
- POST 请求签名时使用实际发送的 JSON 字符串,不要签名一个格式化版本、发送另一个压缩版本。
|
||||
- GET 请求的 `body_hash` 为 `sha256("")`。
|
||||
- `nonce` 会做防重放校验,重试请求需要重新生成 `nonce` 和签名。
|
||||
|
||||
### 2.2 Node.js 签名示例
|
||||
|
||||
```js
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
function sign({ method, pathWithQuery, body = '', timestamp, nonce, appSecret }) {
|
||||
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
|
||||
const base = method.toUpperCase() + pathWithQuery + timestamp + nonce + bodyHash;
|
||||
return crypto.createHmac('sha256', appSecret).update(base).digest('hex');
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 PHP 签名示例
|
||||
|
||||
```php
|
||||
function sign_request(string $method, string $pathWithQuery, string $body, string $timestamp, string $nonce, string $appSecret): string
|
||||
{
|
||||
$bodyHash = hash('sha256', $body);
|
||||
$base = strtoupper($method) . $pathWithQuery . $timestamp . $nonce . $bodyHash;
|
||||
return hash_hmac('sha256', $base, $appSecret);
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 通用响应格式
|
||||
|
||||
成功响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
失败响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 422,
|
||||
"message": "external_order_no 不能为空",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
常见错误码:
|
||||
|
||||
| code | 说明 |
|
||||
| --- | --- |
|
||||
| `401` | 鉴权失败、签名错误、时间戳过期、`nonce` 重复 |
|
||||
| `404` | 订单不存在 |
|
||||
| `409` | 幂等冲突,例如同一个 `external_order_no` 请求内容不一致 |
|
||||
| `422` | 请求参数不合法 |
|
||||
| `500` | 服务端处理失败 |
|
||||
|
||||
## 4. 创建订单
|
||||
|
||||
```text
|
||||
POST /api/open/v1/orders
|
||||
```
|
||||
|
||||
第三方创建订单时只需要传 `external_order_no`。平台会创建一笔待收货订单,后续物品信息由鉴定师在鉴定工作台补充。
|
||||
|
||||
### 4.1 请求参数
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `external_order_no` | string | 是 | 第三方订单号。同一对接客户下必须唯一 |
|
||||
| `service_provider` | string | 否 | 服务方,可选 `anxinyan`、`zhongjian`,默认 `anxinyan` |
|
||||
| `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 | 否 | 扩展信息,当前可不传 |
|
||||
|
||||
### 4.2 最小请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"external_order_no": "THIRD202605080001"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 带可选字段请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"external_order_no": "THIRD202605080002",
|
||||
"service_provider": "anxinyan",
|
||||
"inbound_logistics": {
|
||||
"express_company": "顺丰速运",
|
||||
"tracking_no": "SF1234567890"
|
||||
},
|
||||
"return_address": {
|
||||
"consignee": "张三",
|
||||
"mobile": "13800138000",
|
||||
"province": "浙江省",
|
||||
"city": "杭州市",
|
||||
"district": "西湖区",
|
||||
"detail_address": "文三路 1 号"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 cURL 示例
|
||||
|
||||
```bash
|
||||
curl -X POST 'https://{api-domain}/api/open/v1/orders' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'X-AXY-App-Key: your_app_key' \
|
||||
-H 'X-AXY-Timestamp: 1778227200' \
|
||||
-H 'X-AXY-Nonce: 7b7b2a2f9c9e4d1f' \
|
||||
-H 'X-AXY-Signature: calculated_signature' \
|
||||
-d '{"external_order_no":"THIRD202605080001"}'
|
||||
```
|
||||
|
||||
### 4.5 成功响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "订单已创建",
|
||||
"data": {
|
||||
"idempotent": false,
|
||||
"order": {
|
||||
"customer_id": "CUST001",
|
||||
"customer_code": "CUST001",
|
||||
"external_order_no": "THIRD202605080001",
|
||||
"order_id": 123,
|
||||
"order_no": "AXY20260508120000123",
|
||||
"appraisal_no": "AXY-APP-20260508-1001",
|
||||
"order_status": "pending_shipping",
|
||||
"display_status": "待寄送商品",
|
||||
"payment_status": "paid",
|
||||
"pay_amount": 99,
|
||||
"estimated_finish_time": "2026-05-09 12:00:00",
|
||||
"created_at": "2026-05-08 12:00:00",
|
||||
"timeline": [
|
||||
{
|
||||
"node_code": "created",
|
||||
"node_text": "下单成功",
|
||||
"node_desc": "大客户订单已推送并创建成功",
|
||||
"occurred_at": "2026-05-08 12:00:00"
|
||||
},
|
||||
{
|
||||
"node_code": "pending_shipping",
|
||||
"node_text": "待寄送商品",
|
||||
"node_desc": "请将商品寄送至鉴定中心",
|
||||
"occurred_at": "2026-05-08 12:00:00"
|
||||
}
|
||||
],
|
||||
"inbound_logistics": null,
|
||||
"return_logistics": null,
|
||||
"report_summary": null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.6 幂等规则
|
||||
|
||||
同一个对接客户下,`external_order_no` 作为幂等键:
|
||||
|
||||
- 第一次请求会创建订单。
|
||||
- 后续使用相同 `external_order_no` 且请求内容一致时,不会重复创建订单,会返回已有订单,`data.idempotent` 为 `true`。
|
||||
- 后续使用相同 `external_order_no` 但请求内容不一致时,返回 `409`。
|
||||
|
||||
建议第三方重试创建订单时保持请求 JSON 内容一致,仅重新生成 `timestamp`、`nonce` 和 `signature`。
|
||||
|
||||
## 5. 查询订单
|
||||
|
||||
支持按第三方订单号或平台订单号查询订单进度。
|
||||
|
||||
### 5.1 按第三方订单号查询
|
||||
|
||||
```text
|
||||
GET /api/open/v1/orders/{external_order_no}
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```bash
|
||||
curl -X GET 'https://{api-domain}/api/open/v1/orders/THIRD202605080001' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'X-AXY-App-Key: your_app_key' \
|
||||
-H 'X-AXY-Timestamp: 1778227200' \
|
||||
-H 'X-AXY-Nonce: f0f74a6baf764d8f' \
|
||||
-H 'X-AXY-Signature: calculated_signature'
|
||||
```
|
||||
|
||||
### 5.2 通过查询参数查询
|
||||
|
||||
```text
|
||||
GET /api/open/v1/orders?external_order_no=THIRD202605080001
|
||||
GET /api/open/v1/orders?order_no=AXY20260508120000123
|
||||
```
|
||||
|
||||
### 5.3 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"order": {
|
||||
"customer_id": "CUST001",
|
||||
"customer_code": "CUST001",
|
||||
"external_order_no": "THIRD202605080001",
|
||||
"order_id": 123,
|
||||
"order_no": "AXY20260508120000123",
|
||||
"appraisal_no": "AXY-APP-20260508-1001",
|
||||
"order_status": "report_published",
|
||||
"display_status": "报告已发布",
|
||||
"payment_status": "paid",
|
||||
"pay_amount": 99,
|
||||
"estimated_finish_time": "2026-05-09 12:00:00",
|
||||
"created_at": "2026-05-08 12:00:00",
|
||||
"timeline": [],
|
||||
"inbound_logistics": {
|
||||
"express_company": "顺丰速运",
|
||||
"tracking_no": "SF1234567890",
|
||||
"tracking_status": "submitted",
|
||||
"latest_desc": "客户已提交寄送运单:顺丰速运 SF1234567890,等待鉴定中心签收。",
|
||||
"latest_time": "2026-05-08 12:00:00"
|
||||
},
|
||||
"return_logistics": null,
|
||||
"report_summary": {
|
||||
"report_no": "R202605080001",
|
||||
"report_title": "鉴定报告",
|
||||
"report_status": "published",
|
||||
"publish_time": "2026-05-08 18:00:00",
|
||||
"verify_url": "https://{h5-domain}/verify?id=xxx",
|
||||
"report_page_url": "https://{h5-domain}/report/xxx",
|
||||
"verify_status": "valid"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 订单状态
|
||||
|
||||
常见订单状态如下,最终以接口返回的 `order_status` 和 `display_status` 为准。
|
||||
|
||||
| order_status | display_status | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `pending_shipping` | 待寄送商品 | 订单已创建,等待物品到仓或人工确认收货 |
|
||||
| `received` | 鉴定中心已收货 | 物品已到仓 |
|
||||
| `appraising` | 物品鉴定中 | 鉴定师正在鉴定 |
|
||||
| `generating_report` | 物品鉴定完成 | 鉴定完成,报告生成中 |
|
||||
| `report_published` | 报告已发布 | 报告已发布,可查看报告摘要 |
|
||||
| `return_shipped` | 物品已寄回 | 物品已退回寄出 |
|
||||
| `completed` | 已完成 | 订单完成 |
|
||||
| `pending_supplement` | 需要补充资料 | 需要补充资料 |
|
||||
|
||||
## 7. Webhook 事件回调
|
||||
|
||||
如需接收订单状态变化通知,第三方需向平台提供可公网访问的 `webhook_url`,并由平台开启回调。
|
||||
|
||||
平台会以 POST JSON 方式推送事件:
|
||||
|
||||
| Header | 说明 |
|
||||
| --- | --- |
|
||||
| `Content-Type` | `application/json` |
|
||||
| `X-AXY-App-Key` | 平台分配给该客户的 `app_key` |
|
||||
|
||||
当前 webhook 仅携带 `X-AXY-App-Key`,暂未实现回调签名。如第三方需要回调验签,可与平台另行约定后升级。
|
||||
|
||||
回调超时时间:
|
||||
|
||||
| 项目 | 值 |
|
||||
| --- | --- |
|
||||
| 连接超时 | 3 秒 |
|
||||
| 总超时 | 6 秒 |
|
||||
| 成功判定 | HTTP 状态码为 2xx 且无网络错误 |
|
||||
|
||||
### 7.1 回调报文
|
||||
|
||||
```json
|
||||
{
|
||||
"event_code": "order_created",
|
||||
"event_text": "订单创建",
|
||||
"customer_id": "CUST001",
|
||||
"customer_code": "CUST001",
|
||||
"external_order_no": "THIRD202605080001",
|
||||
"order_no": "AXY20260508120000123",
|
||||
"appraisal_no": "AXY-APP-20260508-1001",
|
||||
"status_code": "pending_shipping",
|
||||
"status_text": "待寄送商品",
|
||||
"occurred_at": "2026-05-08 12:00:00",
|
||||
"data": {},
|
||||
"event_id": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 事件类型
|
||||
|
||||
| event_code | event_text | status_code | status_text |
|
||||
| --- | --- | --- | --- |
|
||||
| `order_created` | 订单创建 | `pending_shipping` | 待寄送商品 |
|
||||
| `inbound_received` | 快递已到仓 | `received` | 鉴定中心已收货 |
|
||||
| `appraising` | 物品鉴定中 | `appraising` | 物品鉴定中 |
|
||||
| `appraisal_finished` | 物品鉴定完成 | `generating_report` | 物品鉴定完成 |
|
||||
| `report_published` | 报告已发布 | `report_published` | 报告已发布 |
|
||||
| `return_shipped` | 物品已寄回 | `return_shipped` | 物品已寄回 |
|
||||
| `completed` | 订单已完成 | `completed` | 已完成 |
|
||||
| `supplement_required` | 需要补充资料 | `pending_supplement` | 需要补充资料 |
|
||||
|
||||
### 7.3 回调接收建议
|
||||
|
||||
第三方接收 webhook 时建议:
|
||||
|
||||
- 使用 `event_id` 做事件幂等,避免重复处理。
|
||||
- 收到事件后返回 HTTP 2xx。
|
||||
- 如需强一致的最新状态,可以收到 webhook 后再调用订单查询接口确认。
|
||||
|
||||
## 8. 对接流程建议
|
||||
|
||||
1. 平台分配 `app_key` 和 `app_secret`。
|
||||
2. 第三方完成签名调试。
|
||||
3. 第三方调用创建订单接口,只传 `external_order_no` 即可。
|
||||
4. 第三方可通过查询接口主动查询订单状态。
|
||||
5. 如启用 webhook,平台在订单状态变化时主动通知第三方。
|
||||
Reference in New Issue
Block a user