You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

515 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# MotherShip 查询接口调用文档
> **第三方正式对接请优先阅读**:同目录 [`api对接文档.md`](./api对接文档.md)v1.1**四路线**MotherShip/Flock × 免账号/登录后)。
> 本文档保留 MotherShip 宿主两步 + 管理端接口细项适合内部运维对照Flock / 登录后字段以对接文档为准。
本文档说明 **MotherShip / Axel** 查询报价相关接口(偏免账号宿主两步),适合内部运维对照使用。
Base URL`https://if.dev.51track.vip`
统一响应格式:
```json
{ "code": 0, "message": "ok", "data": { } }
```
`code !== 0` 为业务/鉴权错误。询价业务失败时 HTTP 可能仍为 `200`,此时看 `data.status === "failed"`
---
## 1. 推荐接口(第三方宿主)
当前推荐使用 **两步宿主接口**(须鉴权):
1. `POST /api/host/quote/candidates`
2. `POST /api/host/quote/submit`
特点:
- 第一步返回提货 / 派送地址候选
- 第二步服务端内部等待询价并同步返回最终报价
- 调用方**不需要**自己轮询 `GET /api/quotes/{id}`
---
## 2. 鉴权(必传)
当前服务器已关闭公开免 Token 模式(`HOST_PUBLIC_API_ENABLED=false`**每次请求**须携带:
```http
Authorization: Bearer <API Key 或 Service Token>
X-Customer-Id: <Customer ID>
Content-Type: application/json
```
| 字段 | 说明 |
|------|------|
| `Authorization` | `Bearer` + 我方发放的凭证 |
| `X-Customer-Id` | 客户 ID必须与凭证绑定一致 |
| `Content-Type` | 固定 `application/json` |
### 2.1 凭证来源(二选一)
| 类型 | 形态 | 来源 |
|------|------|------|
| **客户 API Key推荐给第三方** | 通常以 `chj_` 开头 | 管理端「客户管理」新建客户 / 轮换 Key 后发放 |
| Service Token | 自定义字符串,如 `demo-host-token` | 服务器 `.env``HOST_SERVICE_TOKENS`(联调/内网) |
第三方正式对接请使用管理端发放的 **API Key**,不要把 Key 写进前端页面或公开仓库。
### 2.2 请求头示例
```http
Authorization: Bearer chj_xxxxxxxxxxxxxxxxxxxxx
X-Customer-Id: CUST_003
Content-Type: application/json
```
联调可用 env Token若服务器已配置
```http
Authorization: Bearer demo-host-token
X-Customer-Id: CUST_001
Content-Type: application/json
```
### 2.3 鉴权错误
| HTTP | message | 说明 |
|------|---------|------|
| 401 | 缺少 Authorization 头 | 未带 Bearer |
| 401 | Service Token 无效 | Key/Token 错误或已轮换失效 |
| 403 | customer_id 与令牌租户不匹配 | `X-Customer-Id` 与 Key 绑定不一致 |
| 401 | 令牌无效或已过期 | 误用了管理员 JWT应使用 API Key / Service Token |
### 2.4 Apifox 环境变量
| 变量 | 示例值 |
|------|--------|
| `baseUrl` | `https://if.dev.51track.vip` |
| `token` | 管理端发放的 `chj_...` 或联调 `demo-host-token` |
| `customerId` | 与 Token 绑定的客户 ID`CUST_001` |
Headers
- `Authorization``Bearer {{token}}`
- `X-Customer-Id``{{customerId}}`
- `Content-Type``application/json`
---
## 3. 第一步:获取联想地址候选
### 接口
```http
POST /api/host/quote/candidates
```
### 请求头
```http
Authorization: Bearer <API Key>
X-Customer-Id: <Customer ID>
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` | 否 | 建议传,格式 `12345``12345-6789` |
| `cargo.weight.value` | 是 | 单托重量 |
| `cargo.weight.unit` | 是 | `lb`、`kg` 或 `t`/`tonne`(公制吨;禁止 `ton`/`tons` |
| `cargo.dimensions.*` | 是 | 单托长宽高 |
| `cargo.dimensions.unit` | 是 | `in`、`cm` 或 `m` |
| `cargo.pallet_count` | 是 | 托盘数125 |
| `cargo.cargo_type` | 是 | 见下方枚举 |
**货物类型 `cargo_type`**
`general_freight` · `machinery` · `furniture` · `electronics` · `building_materials` · `auto_parts` · `food_nonperishable` · `apparel` · `other`
服务端会自动把 `lb`/`kg`/`t`、`in`/`cm`/`m` 换算为 MotherShip 需要的英制单位(小数进一)。
### 成功响应示例
```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. 第二步提交时传回选中的**完整候选对象**(不要只传 `option_id`
不要使用 `selectable: false` 的候选(可能带 `unavailable_reason`)。
---
## 4. 第二步:提交候选并获取最终报价
### 接口
```http
POST /api/host/quote/submit
```
### 请求头
与第一步相同。
### 请求体
```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` 必须来自第一步
- 候选对象必须是第一步列表中的完整对象(`option_id` 须匹配)
- HTTP 连接可能保持 **10420 秒**;客户端 / Nginx 超时建议 ≥ **420 秒**
- **不会**返回 `processing` 让你继续轮询;服务端内部完成等待
### 成功响应示例
```json
{
"code": 0,
"message": "ok",
"data": {
"quote_id": "QTE_20260630_0003",
"request_id": "xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx",
"status": "done",
"currency": "USD",
"valid_until": "2026-06-30T10:30:00.000Z",
"source_type": "rpa",
"quotes": [
{
"service_level": "standard",
"rate_option": "lowest",
"carrier": "Frontline Freight",
"transit_days": "Est. 5 business days",
"final_total": 337.06
}
]
}
}
```
| 字段 | 说明 |
|------|------|
| `status` | `done` 成功;`failed` 失败(看 `error_message` |
| `quotes[].final_total` | **对客户展示价USD含加价** |
| `quotes[].carrier` | 承运商 |
| `quotes[].transit_days` | 时效 |
| `valid_until` | 报价有效期 |
---
## 5. 调用步骤总结
1. 带鉴权头调 `POST /api/host/quote/candidates`
2. 保存 `host_session_id`,让用户各选一条可用地址
3. 带鉴权头调 `POST /api/host/quote/submit`
4. 直接展示最终报价
### 第三方需要做
- API Key 放服务端,不暴露前端
- 每次请求带 `Authorization` + `X-Customer-Id`
- 第一步做地址选择 UI第二步 Loading超时 ≥ 420s
### 第三方不需要做
- 不需要 `GET /api/quotes/{id}` 轮询
- 不需要自己做公制 → 英制换算(支持 `kg`/`t`/`cm`/`m`,服务端统一进一取整为 lb/in
---
## 6. Apifox / cURL
### Apifox
| 步骤 | 方法 | URL |
|------|------|-----|
| 1 | POST | `{{baseUrl}}/api/host/quote/candidates` |
| 2 | POST | `{{baseUrl}}/api/host/quote/submit` |
第二步超时建议:`420000` ms。
### cURL第一步
```bash
curl -X POST "https://if.dev.51track.vip/api/host/quote/candidates" \
-H "Authorization: Bearer <API Key>" \
-H "X-Customer-Id: CUST_001" \
-H "Content-Type: application/json" \
--data-binary @host-candidates-req.json
```
PowerShell本机测公网不要写 `127.0.0.1`,不要加 `:30325`
```powershell
curl.exe -s -w "`nHTTP: %{http_code}`n" `
-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"
```
---
## 7. 常见错误
| code | HTTP | 说明 | 处理 |
|------|------|------|------|
| `UNAUTHORIZED` | 401 | 缺少或无效 Token/API Key | 检查 Bearer 与客户绑定 |
| `FORBIDDEN` | 403 | 客户 ID 与令牌不匹配 | 核对 `X-Customer-Id` |
| `VALIDATION_FAILED` | 400 | 参数不合法 / JSON 无效 | 检查字段、单位、州码 |
| `SESSION_EXPIRED` | 404 | `host_session_id` 过期 | 重新调第一步 |
| `ADDRESS_SESSION_MISMATCH` | 400 | 候选不在本次联想结果中 | 使用第一步返回的完整对象 |
| `ADDRESS_NOT_SELECTABLE` | 400 | 选了不可用候选 | 改用 `selectable: true` |
| `QUOTE_TIMEOUT` | 504 | 服务端等待超时 | 稍后重试 |
| `RATE_LIMITED` | 429 | 限流 | 降低频率 |
---
## 8. 客户管理接口(管理员)
供**管理端 / 内部运维**使用,不提供给第三方宿主直接调用。
### 8.1 鉴权
```http
Authorization: Bearer <Admin JWT>
Content-Type: application/json
```
管理员 JWT 通过 `POST /api/auth/login` 获取(账号密码登录)。
### 8.2 获取客户列表
```http
GET /api/admin/customers?page=1&size=10&keyword=CUST_001
```
| 参数 | 必填 | 说明 |
|------|------|------|
| `page` | 是 | 页码,从 1 开始 |
| `size` | 是 | 每页 1100 |
| `keyword` | 否 | 按客户 ID / 名称模糊搜索 |
成功时 `data.list[]` 主要字段:
| 字段 | 说明 |
|------|------|
| `customer_id` | 客户 ID |
| `status` | `active` / `disabled` |
| `embed_password_set` | 是否已设 `/embed-demo` 密码 |
| `active_api_key` | 当前有效 API Key历史未保存原文时可能为 `null` |
| `api_keys[]` | Key 摘要(不含完整原文,仅前缀等) |
### 8.3 新建客户
```http
POST /api/admin/customers
```
```json
{
"name": "演示客户 003",
"remark": "重点客户",
"embed_password": "123456"
}
```
| 字段 | 必填 | 说明 |
|------|------|------|
| `name` | 是 | 客户名称 |
| `remark` | 否 | 备注 |
| `embed_password` | 否 | `/embed-demo` 登录密码;不传默认 `123456` |
响应中 `api_key` **仅在新建时额外返回一次**;同时写入 `active_api_key`。请立即保存发给第三方。
### 8.4 更新客户
```http
PATCH /api/admin/customers/{customer_id}
```
可更新:`name`、`remark`、`status``active`/`disabled`)、`embed_password`(至少 6 位)。
### 8.5 轮换 API Key
```http
POST /api/admin/customers/{customer_id}/rotate-key
```
- 原有效 Key 立即失效
- 响应中的 `api_key``active_api_key` 为新 Key
- 轮换后须通知第三方更换凭证
### 8.6 承运商官网账密(管理端)
```http
GET /api/admin/customers/{customer_id}/provider-credentials
PUT /api/admin/customers/{customer_id}/provider-credentials
```
用于绑定客户在 MotherShip / Flock 官网的登录账密RPA 使用),**非第三方宿主对接接口**。
PUT 请求体示例:
```json
{
"provider": "mothership",
"email": "user@example.com",
"password": "********"
}
```
| 约束 | 说明 |
|------|------|
| `provider` | 仅 `mothership``flock` |
| 写入策略 | 仅允许首次绑定;已绑定后不可修改 / 清除 |
| 清除 | 不支持 `clear`;更换需新建客户 |
---
## 9. 嵌入演示登录
`/embed-demo` 演示页使用,不是正式宿主 API。
### 9.1 登录
```http
POST /api/embed-demo/login
```
```json
{
"customer_id": "CUST_003",
"password": "cust003@2026"
}
```
- 密码以管理端「客户管理」中为该客户设置的为准
- 成功后写入 HttpOnly Cookie`embed_demo_session`
### 9.2 当前会话 / 退出
```http
GET /api/embed-demo/me
POST /api/embed-demo/logout
```
`me` 依赖登录 Cookie返回当前客户及加价配置。
---
## 10. 其它渠道说明(非推荐宿主对接)
以下接口同样需要 Service Token / API Key但**返回 `processing`,需客户端轮询**,不作为第三方默认同步对接方案:
| 渠道 | 提交 | 轮询 |
|------|------|------|
| MotherShip 旧三步 | `POST /api/quotes` 等 | `GET /api/quotes/{quote_id}` |
| Priority1 | `POST /api/priority1/quotes` | 同上 |
| Flock | `POST /api/flock/quotes` | 同上 |
第三方正式对接请优先使用本文档第 14 节的两步宿主接口。
---
## 11. 联系与支持
- Token / API Key 失效或需开通新客户:联系我方运维 / 管理端操作
- `X-Customer-Id` 必须与发放凭证绑定一致,不可串用
- 老客户若 `active_api_key` 为空:在管理端「轮换 Key」一次后再查看