|
|
# 外部系统 API 对接说明
|
|
|
|
|
|
> 完整对接指南(含美美与共示例、前端职责、自测方法)见 **[第三方对接指南](./第三方对接指南.md)**。
|
|
|
|
|
|
Base URL:`https://<你的域名>`(示例:`https://if.dev.51track.vip`)
|
|
|
|
|
|
## 响应格式
|
|
|
|
|
|
```json
|
|
|
{ "code": 0, "message": "ok", "data": { } }
|
|
|
```
|
|
|
|
|
|
`code !== 0` 时为业务错误;询价业务失败时 HTTP 可能仍为 200,`data.status === "failed"`。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 方式 A:宿主两步接口(推荐)
|
|
|
|
|
|
**接口路径不变**,鉴权由服务器 `.env` 控制:
|
|
|
|
|
|
| 模式 | `HOST_PUBLIC_API_ENABLED` | 请求头 |
|
|
|
|------|---------------------------|--------|
|
|
|
| 公开(联调/内网) | `true` | 只需 `Content-Type: application/json` |
|
|
|
| **鉴权(对接第三方)** | `false` | 见下方 Token 头 |
|
|
|
|
|
|
| 步骤 | 方法 | 路径 | 说明 |
|
|
|
|------|------|------|------|
|
|
|
| 1 | POST | `/api/host/quote/candidates` | 地址 + 货物 → 联想候选 + `host_session_id` |
|
|
|
| 2 | POST | `/api/host/quote/submit` | 确认候选 → **同步返回最终报价**(服务端内部轮询) |
|
|
|
|
|
|
**公开模式** 无需 `Authorization` / `X-Customer-Id`。只需:
|
|
|
|
|
|
```http
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
**鉴权模式** 须携带(Token 由我方在 `HOST_SERVICE_TOKENS` 中配置后发放):
|
|
|
|
|
|
```http
|
|
|
Authorization: Bearer <Service Token>
|
|
|
X-Customer-Id: <Customer ID>
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
服务端 `.env` 示例(为美美与共单独发 Token):
|
|
|
|
|
|
```env
|
|
|
HOST_PUBLIC_API_ENABLED=false
|
|
|
HOST_SERVICE_TOKENS={"meimei-2026":{"customerId":"CUST_001","permissions":["pricing:markup:write"]}}
|
|
|
CUSTOMER_REGISTRY=CUST_001
|
|
|
```
|
|
|
|
|
|
### 1. 联想地址
|
|
|
|
|
|
**请求体:** 见 [`host-candidates-req.example.json`](./host-candidates-req.example.json)
|
|
|
|
|
|
**成功响应 `data` 字段:**
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|------|------|
|
|
|
| `host_session_id` | UUID,第二步必传;30 分钟有效 |
|
|
|
| `pickup_candidates` | 提货候选列表 |
|
|
|
| `delivery_candidates` | 派送候选列表 |
|
|
|
| `requires_selection` | 是否需用户从多条候选中选择 |
|
|
|
|
|
|
候选对象字段:`option_id`、`display_label`、`formatted_address`、`street`、`city`、`state`、`zip`、`selectable`、`unavailable_reason`
|
|
|
|
|
|
### 2. 确认并取报价
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"host_session_id": "第一步返回的 UUID",
|
|
|
"pickup_candidate": { "option_id": "...", "display_label": "...", "formatted_address": "...", "street": "...", "city": "...", "state": "CA", "zip": "90001" },
|
|
|
"delivery_candidate": { "option_id": "...", "display_label": "...", "formatted_address": "...", "street": "...", "city": "...", "state": "TX", "zip": "75201" }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
`pickup_candidate` / `delivery_candidate` 须为第一步返回列表中的完整对象(`option_id` 须匹配)。
|
|
|
|
|
|
**成功响应 `data`:** 与 `GET /api/quotes/{id}` 相同,主要字段:
|
|
|
|
|
|
| 字段 | 说明 |
|
|
|
|------|------|
|
|
|
| `status` | `done` 成功;`failed` 失败 |
|
|
|
| `quotes[]` | 多档报价 |
|
|
|
| `quotes[].final_total` | **对客户展示价**(USD,含加价) |
|
|
|
| `quotes[].carrier` | 承运商 |
|
|
|
| `quotes[].transit_days` | 时效 |
|
|
|
| `error_message` | `status=failed` 时的原因 |
|
|
|
|
|
|
**注意:**
|
|
|
|
|
|
- 第二步 HTTP 连接可能保持 **10–420 秒**,Nginx 须设 `proxy_read_timeout 420s;`
|
|
|
- 宿主**无需**再调 `GET /api/quotes/{id}` 轮询
|
|
|
|
|
|
### 货物字段(第一步 `cargo`)
|
|
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|
|------|------|------|
|
|
|
| `weight.value` | number | 单托重量 |
|
|
|
| `weight.unit` | `lb` \| `kg` | 重量单位 |
|
|
|
| `dimensions.length/width/height` | number | 单托尺寸 |
|
|
|
| `dimensions.unit` | `in` \| `cm` | 尺寸单位 |
|
|
|
| `pallet_count` | number | 托盘数 1–25 |
|
|
|
| `cargo_type` | string | 见下方枚举 |
|
|
|
|
|
|
**货物类型:** `general_freight` · `machinery` · `furniture` · `electronics` · `building_materials` · `auto_parts` · `food_nonperishable` · `apparel` · `other`
|
|
|
|
|
|
### 方式 A 错误码
|
|
|
|
|
|
| code | HTTP | 说明 |
|
|
|
|------|------|------|
|
|
|
| `VALIDATION_FAILED` | 400 | 参数无效;若 message 为「请求体格式无效」多为 JSON 格式错误 |
|
|
|
| `UNAUTHORIZED` | 401 | 鉴权模式下缺少或无效的 `Authorization` |
|
|
|
| `SESSION_EXPIRED` | 404 | `host_session_id` 过期或无效 |
|
|
|
| `ADDRESS_SESSION_MISMATCH` | 400 | 候选不在本次联想结果中 |
|
|
|
| `ADDRESS_NOT_SELECTABLE` | 400 | 选了不可用的候选 |
|
|
|
| `QUOTE_TIMEOUT` | 504 | 服务端轮询超时 |
|
|
|
| `RATE_LIMITED` | 429 | 限流 |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 方式 B:Token 三步接口(旧流程,需客户端轮询)
|
|
|
|
|
|
**前置条件:** 在请求头携带 Token(与方式 A 鉴权模式相同)。
|
|
|
|
|
|
```http
|
|
|
Authorization: Bearer <Service Token>
|
|
|
X-Customer-Id: <Customer ID>
|
|
|
Content-Type: application/json
|
|
|
```
|
|
|
|
|
|
Token 在 `.env` 的 `HOST_SERVICE_TOKENS` 中配置。
|
|
|
|
|
|
| 步骤 | 方法 | 路径 |
|
|
|
|------|------|------|
|
|
|
| 1 | POST | `/api/addresses/mothership-candidates` |
|
|
|
| 2 | POST | `/api/quotes` |
|
|
|
| 3 | GET | `/api/quotes/{quote_id}`(每 2 秒轮询,最长约 7 分钟) |
|
|
|
|
|
|
第二步 body 须含 `customer_id`、`request_id`(UUID v4)、经 MotherShip 确认的 `pickup_address` / `delivery_address` 及货物字段。详情见 [第三方对接指南 §6](./第三方对接指南.md#6-方式btoken-三步接口)。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 快速自测(方式 A)
|
|
|
|
|
|
**Windows PowerShell(推荐用 JSON 文件,避免引号转义问题):**
|
|
|
|
|
|
```powershell
|
|
|
curl.exe -s -X POST "https://if.dev.51track.vip/api/host/quote/candidates" `
|
|
|
-H "Content-Type: application/json" `
|
|
|
--data-binary "@deploy/host-candidates-req.example.json"
|
|
|
```
|
|
|
|
|
|
返回 `"code":0` 且含 `host_session_id` 即成功。
|
|
|
|
|
|
**Linux / macOS:**
|
|
|
|
|
|
```bash
|
|
|
curl -s -X POST "https://if.dev.51track.vip/api/host/quote/candidates" \
|
|
|
-H "Content-Type: application/json" \
|
|
|
--data-binary "@deploy/host-candidates-req.example.json"
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
*文档版本:2026-06-30*
|