|
|
# MotherShip 查询接口调用文档
|
|
|
|
|
|
本文档只说明 **MotherShip / Axel** 查询报价接口如何调用,适合直接发给第三方开发人员使用。
|
|
|
|
|
|
Base URL:`https://if.dev.51track.vip`
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. 推荐接口
|
|
|
|
|
|
当前使用 **两步宿主接口**(须鉴权):
|
|
|
|
|
|
1. `POST /api/host/quote/candidates`
|
|
|
2. `POST /api/host/quote/submit`
|
|
|
|
|
|
特点:
|
|
|
|
|
|
- 第一步返回联想地址候选
|
|
|
- 第二步服务端内部等待并轮询
|
|
|
- 调用方**不需要自己轮询**
|
|
|
|
|
|
---
|
|
|
|
|
|
## 2. 鉴权(必传)
|
|
|
|
|
|
当前服务器已开启鉴权(`HOST_PUBLIC_API_ENABLED=false`),**每次请求**须携带以下请求头:
|
|
|
|
|
|
```http
|
|
|
Authorization: Bearer <Service Token>
|
|
|
X-Customer-Id: CUST_001
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
| 字段 | 值 | 说明 |
|
|
|
|------|-----|------|
|
|
|
| `Authorization` | `Bearer <Service Token>` | 我方单独发放的 API Token |
|
|
|
| `X-Customer-Id` | `CUST_001` | 固定客户 ID,须与 Token 绑定一致 |
|
|
|
|
|
|
**示例(联调 Token):**
|
|
|
|
|
|
```http
|
|
|
Authorization: Bearer demo-host-token
|
|
|
X-Customer-Id: CUST_001
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
> 生产环境 Token 由我方另行发放,格式同上;请勿将 Token 写入前端页面或公开仓库。
|
|
|
|
|
|
### 鉴权错误
|
|
|
|
|
|
| HTTP | message | 说明 |
|
|
|
|------|---------|------|
|
|
|
| 401 | 缺少 Authorization 头 | 未带 `Authorization: Bearer ...` |
|
|
|
| 401 | Service Token 无效 | Token 拼写错误或不在白名单 |
|
|
|
| 401 | 令牌无效或已过期 | 误用了管理员 JWT,应使用 Service Token |
|
|
|
|
|
|
### Apifox 环境变量建议
|
|
|
|
|
|
| 变量 | 示例值 |
|
|
|
|------|--------|
|
|
|
| `baseUrl` | `https://if.dev.51track.vip` |
|
|
|
| `token` | `demo-host-token`(联调)或我方发放的生产 Token |
|
|
|
| `customerId` | `CUST_001` |
|
|
|
|
|
|
在「Auth」或「Headers」中配置:
|
|
|
|
|
|
- `Authorization`:`Bearer {{token}}`
|
|
|
- `X-Customer-Id`:`{{customerId}}`
|
|
|
- `Content-Type`:`application/json`
|
|
|
|
|
|
---
|
|
|
|
|
|
## 3. 第一步:获取联想地址候选
|
|
|
|
|
|
### 接口
|
|
|
|
|
|
```http
|
|
|
POST /api/host/quote/candidates
|
|
|
```
|
|
|
|
|
|
### 请求头示例
|
|
|
|
|
|
```http
|
|
|
Authorization: Bearer demo-host-token
|
|
|
X-Customer-Id: CUST_001
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
### 请求体
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"pickup_address": {
|
|
|
"street": "1234 Warehouse Blvd",
|
|
|
"city": "Los Angeles",
|
|
|
"state": "CA",
|
|
|
"zip": "90001"
|
|
|
},
|
|
|
"delivery_address": {
|
|
|
"street": "5678 Distribution Dr",
|
|
|
"city": "Dallas",
|
|
|
"state": "TX",
|
|
|
"zip": "75201"
|
|
|
},
|
|
|
"cargo": {
|
|
|
"weight": { "value": 500, "unit": "kg" },
|
|
|
"dimensions": { "length": 120, "width": 100, "height": 150, "unit": "cm" },
|
|
|
"pallet_count": 2,
|
|
|
"cargo_type": "general_freight"
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 字段说明
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|------|------|
|
|
|
| `pickup_address` | 提货草稿地址 |
|
|
|
| `delivery_address` | 派送草稿地址 |
|
|
|
| `street/city/state` | 必填,`state` 为美国州二字码 |
|
|
|
| `zip` | 可选,建议传 |
|
|
|
| `cargo.weight.unit` | `kg` 或 `lb` |
|
|
|
| `cargo.dimensions.unit` | `cm` 或 `in` |
|
|
|
| `cargo.pallet_count` | 托盘数,1–25 |
|
|
|
| `cargo.cargo_type` | `general_freight` 等 |
|
|
|
|
|
|
### 成功响应示例
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"code": 0,
|
|
|
"message": "ok",
|
|
|
"data": {
|
|
|
"host_session_id": "2dd352e6-9a1d-4563-8f13-ebff18aabdb9",
|
|
|
"pickup_candidates": [
|
|
|
{
|
|
|
"option_id": "Eisx...",
|
|
|
"display_label": "1234 Warehouse Street, Los Angeles, CA, USA",
|
|
|
"formatted_address": "1234 Warehouse Street, Los Angeles, CA, USA",
|
|
|
"street": "1234 Warehouse Street",
|
|
|
"city": "Los Angeles",
|
|
|
"state": "CA",
|
|
|
"zip": "90001",
|
|
|
"selectable": true
|
|
|
}
|
|
|
],
|
|
|
"delivery_candidates": [
|
|
|
{
|
|
|
"option_id": "EihE...",
|
|
|
"display_label": "Distribution Dr, Wilmer, Dallas, TX, USA",
|
|
|
"formatted_address": "Distribution Dr, Wilmer, Dallas, TX, USA",
|
|
|
"street": "5678 Distribution Dr, Wilmer",
|
|
|
"city": "Dallas",
|
|
|
"state": "TX",
|
|
|
"zip": "75201",
|
|
|
"selectable": true
|
|
|
}
|
|
|
],
|
|
|
"requires_selection": true
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 第一步调用后的处理
|
|
|
|
|
|
1. 保存 `data.host_session_id`(约 30 分钟有效)
|
|
|
2. 从 `pickup_candidates` 中选择 1 条 `selectable: true`
|
|
|
3. 从 `delivery_candidates` 中选择 1 条 `selectable: true`
|
|
|
4. 将选中的**完整候选对象**用于第二步请求
|
|
|
|
|
|
不要使用 `selectable: false` 的候选。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 4. 第二步:提交候选并直接获取最终报价
|
|
|
|
|
|
### 接口
|
|
|
|
|
|
```http
|
|
|
POST /api/host/quote/submit
|
|
|
```
|
|
|
|
|
|
### 请求头
|
|
|
|
|
|
与第一步相同(须带 `Authorization` 与 `X-Customer-Id`)。
|
|
|
|
|
|
### 请求体
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"host_session_id": "2dd352e6-9a1d-4563-8f13-ebff18aabdb9",
|
|
|
"pickup_candidate": {
|
|
|
"option_id": "Eisx...",
|
|
|
"display_label": "1234 Warehouse Street, Los Angeles, CA, USA",
|
|
|
"formatted_address": "1234 Warehouse Street, Los Angeles, CA, USA",
|
|
|
"street": "1234 Warehouse Street",
|
|
|
"city": "Los Angeles",
|
|
|
"state": "CA",
|
|
|
"zip": "90001",
|
|
|
"selectable": true
|
|
|
},
|
|
|
"delivery_candidate": {
|
|
|
"option_id": "EihE...",
|
|
|
"display_label": "Distribution Dr, Wilmer, Dallas, TX, USA",
|
|
|
"formatted_address": "Distribution Dr, Wilmer, Dallas, TX, USA",
|
|
|
"street": "5678 Distribution Dr, Wilmer",
|
|
|
"city": "Dallas",
|
|
|
"state": "TX",
|
|
|
"zip": "75201",
|
|
|
"selectable": true
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 注意
|
|
|
|
|
|
- `host_session_id` 必须来自第一步返回值
|
|
|
- `pickup_candidate` / `delivery_candidate` 必须是第一步候选列表中的**完整对象**
|
|
|
- 第二步会等待 10–30 秒,最长约 420 秒
|
|
|
- 第二步**不会**返回 `processing` 让你继续轮询;服务端会自己处理轮询
|
|
|
|
|
|
### 成功响应示例
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"code": 0,
|
|
|
"message": "ok",
|
|
|
"data": {
|
|
|
"quote_id": "QTE_20260630_0003",
|
|
|
"status": "done",
|
|
|
"currency": "USD",
|
|
|
"valid_until": "2026-06-30T10:30:00.000Z",
|
|
|
"quotes": [
|
|
|
{
|
|
|
"service_level": "standard",
|
|
|
"rate_option": "lowest",
|
|
|
"carrier": "Frontline Freight",
|
|
|
"transit_days": "Est. 5 business days",
|
|
|
"final_total": 337.06
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 应展示给用户的字段
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|------|------|
|
|
|
| `quotes[].final_total` | 最终展示价(USD) |
|
|
|
| `quotes[].carrier` | 承运商 |
|
|
|
| `quotes[].transit_days` | 时效 |
|
|
|
| `valid_until` | 报价有效期 |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 5. 调用步骤总结
|
|
|
|
|
|
### 业务步骤
|
|
|
|
|
|
1. 带鉴权头调 `POST /api/host/quote/candidates`
|
|
|
2. 取得 `host_session_id`
|
|
|
3. 让用户在候选地址中各选一条可用地址
|
|
|
4. 带鉴权头调 `POST /api/host/quote/submit`
|
|
|
5. 直接拿最终报价并展示
|
|
|
|
|
|
### 第三方系统需要做的事
|
|
|
|
|
|
- 在服务端保存 Token,**不要**暴露在前端
|
|
|
- 每次请求携带 `Authorization` + `X-Customer-Id: CUST_001`
|
|
|
- 第一步展示候选地址选择 UI
|
|
|
- 第二步显示 Loading(建议超时 ≥ 420 秒)
|
|
|
- 第二步返回后展示报价
|
|
|
|
|
|
### 第三方系统不需要做的事
|
|
|
|
|
|
- 不需要 `GET /api/quotes/{id}` 轮询
|
|
|
- 不需要自己做 kg/cm 到 lb/in 的换算
|
|
|
|
|
|
---
|
|
|
|
|
|
## 6. 单位说明
|
|
|
|
|
|
接口支持:
|
|
|
|
|
|
- 重量:`kg` / `lb`
|
|
|
- 尺寸:`cm` / `in`
|
|
|
|
|
|
例如:
|
|
|
|
|
|
```json
|
|
|
"weight": { "value": 500, "unit": "kg" },
|
|
|
"dimensions": { "length": 120, "width": 100, "height": 150, "unit": "cm" }
|
|
|
```
|
|
|
|
|
|
服务端会自动换算为 MotherShip 需要的英制单位。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 7. Apifox 测试方法
|
|
|
|
|
|
### 环境变量
|
|
|
|
|
|
| 变量 | 值 |
|
|
|
|------|-----|
|
|
|
| `baseUrl` |https://if.dev.51track.vip |
|
|
|
| `token` | `demo-host-token` |
|
|
|
| `customerId` | `CUST_001` |
|
|
|
|
|
|
### 第一步
|
|
|
|
|
|
- 方法:`POST`
|
|
|
- URL:`{{baseUrl}}/api/host/quote/candidates`
|
|
|
- Headers:
|
|
|
- `Authorization`:`Bearer {{token}}`
|
|
|
- `X-Customer-Id`:`{{customerId}}`
|
|
|
- `Content-Type`:`application/json`
|
|
|
- Body:JSON(可参考 `deploy/host-candidates-req.example.json`)
|
|
|
|
|
|
### 第二步
|
|
|
|
|
|
- 方法:`POST`
|
|
|
- URL:`{{baseUrl}}/api/host/quote/submit`
|
|
|
- Headers:与第一步相同
|
|
|
- Body:填入第一步返回的 `host_session_id` 和选中的完整候选对象
|
|
|
|
|
|
Apifox 请求超时建议:`420000` ms(420 秒)
|
|
|
|
|
|
### cURL 示例(第一步)
|
|
|
|
|
|
```bash
|
|
|
curl -X POST "https://if.dev.51track.vip/api/host/quote/candidates" \
|
|
|
-H "Authorization: Bearer demo-host-token" \
|
|
|
-H "X-Customer-Id: CUST_001" \
|
|
|
-H "Content-Type: application/json" \
|
|
|
--data-binary @deploy/host-candidates-req.example.json
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 8. 常见错误
|
|
|
|
|
|
| code | HTTP | 说明 | 处理方式 |
|
|
|
|------|------|------|----------|
|
|
|
| `UNAUTHORIZED` | 401 | 缺少或无效 Token | 检查 `Authorization`、`X-Customer-Id` |
|
|
|
| `VALIDATION_FAILED` | 400 | 参数不合法 | 检查 JSON、字段名、单位值 |
|
|
|
| `SESSION_EXPIRED` | 404 | 会话过期 | 重新调第一步 |
|
|
|
| `ADDRESS_SESSION_MISMATCH` | 400 | 第二步候选与第一步不一致 | 使用第一步返回的完整候选对象 |
|
|
|
| `ADDRESS_NOT_SELECTABLE` | 400 | 选了不可用候选 | 改用 `selectable: true` 的候选 |
|
|
|
| `QUOTE_TIMEOUT` | 504 | 服务端等待超时 | 稍后重试 |
|
|
|
| `RATE_LIMITED` | 429 | 请求过于频繁 | 降低调用频率 |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 9. 联系与支持
|
|
|
|
|
|
- Token 失效或需单独开通生产 Token,请联系我方运维
|
|
|
- `X-Customer-Id` 当前固定为 `CUST_001`,须与发放的 Token 一致
|