12 KiB
卡派查价 — 第三方系统对接指南
本文档面向宿主业务系统(如美美与共)开发方,说明如何通过 HTTP API 接入实时卡派(LTL)询价。
接口速查见
API.md。示例 JSON 见host-candidates-req.example.json。
1. 对接前准备
| 项 | 说明 |
|---|---|
| Base URL | 由我方提供,例如 https://if.dev.51track.vip |
| 推荐方式 | 方式 A:两步宿主接口,免 Token,服务端同步返回报价 |
| 备用方式 | 方式 B:Token + 三步接口 + 宿主自行轮询(后期启用鉴权时使用) |
| 协议 | HTTPS + JSON,UTF-8 |
服务器开关(我方运维配置):
HOST_PUBLIC_API_ENABLED=true
HOST_PUBLIC_DEFAULT_CUSTOMER_ID=CUST_001
2. 方式 A:两步接口(推荐,美美与共当前使用)
2.1 流程概览
sequenceDiagram
participant 用户
participant 宿主前端 as 宿主前端
participant 查价 as 查价 API
用户->>宿主前端: 填写地址 + 货物,点「获取报价」
宿主前端->>查价: ① POST /api/host/quote/candidates
查价-->>宿主前端: 候选列表 + host_session_id
宿主前端->>用户: 展示候选,选择提货/派送地址
用户->>宿主前端: 确认候选
宿主前端->>查价: ② POST /api/host/quote/submit
Note over 查价: 内部提交询价 + 轮询,10–420 秒
查价-->>宿主前端: status=done + quotes
宿主前端->>用户: 展示 final_total 等
| 调用次序 | 接口 | 宿主做什么 | 查价做什么 |
|---|---|---|---|
| 第 1 次 | POST /api/host/quote/candidates |
传地址 + 货物 | 返回联想候选 + host_session_id |
| 第 2 次 | POST /api/host/quote/submit |
传会话 ID + 用户选的候选 | 内部轮询,直接返回最终报价 |
宿主无需: Token、GET 轮询、quote_id 管理。
宿主需要: 地址候选选择 UI、报价结果 UI、第 2 步 Loading(约 10–30 秒,最长约 7 分钟)。
2.2 鉴权
方式 A 不需要任何 Authorization 头,只需:
Content-Type: application/json
2.3 第一步:联想地址 + 暂存货物
POST /api/host/quote/candidates
Content-Type: application/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 |
是 | 货物信息(第一步传入后由服务端暂存,第二步无需重复传) |
成功响应示例:
{
"code": 0,
"message": "ok",
"data": {
"host_session_id": "eb75548a-2c0b-4282-becd-ca3a0f5a3c15",
"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
}
}
前端处理:
- 用
display_label展示给用户。 - 仅允许选择
selectable: true的项;不可选项展示unavailable_reason。 - 保存
host_session_id(30 分钟有效)和用户选中的完整候选对象。
2.4 第二步:确认候选并取报价(同步)
POST /api/host/quote/submit
Content-Type: application/json
请求体:
{
"host_session_id": "eb75548a-2c0b-4282-becd-ca3a0f5a3c15",
"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 |
是 | 第一步返回的 UUID |
pickup_candidate |
是 | 第一步 pickup_candidates 中用户选中项(完整对象) |
delivery_candidate |
是 | 第一步 delivery_candidates 中用户选中项(完整对象) |
成功响应(节选):
{
"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)、carrier、transit_days。
失败: HTTP 200 时 data.status 可能为 failed,读 error_message;HTTP 504 表示服务端轮询超时。
2.5 美美与共前端职责
| 模块 | 说明 |
|---|---|
| 表单 | 收集地址(仓库代码需先转为 street/city/state/zip)和货物 |
| 地址候选 UI | 第 1 步后展示 pickup_candidates / delivery_candidates 供用户选择 |
| 报价结果 UI | 第 2 步后展示 quotes 列表 |
| Loading | 第 2 步显示「正在查询报价,约需 10–30 秒」,禁止重复提交 |
| 不需要 | Token、轮询、quote_id 管理 |
2.6 美美与共调用示例(JavaScript)
// 第 1 步:联想
async function fetchCandidates(form) {
const res = await fetch("https://if.dev.51track.vip/api/host/quote/candidates", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
pickup_address: form.pickup,
delivery_address: form.delivery,
cargo: form.cargo,
}),
});
const json = await res.json();
if (json.code !== 0) throw new Error(json.message);
return json.data; // { host_session_id, pickup_candidates, delivery_candidates }
}
// 第 2 步:确认并取报价(一次请求,无需轮询)
async function submitQuote(hostSessionId, pickupCandidate, deliveryCandidate) {
const res = await fetch("https://if.dev.51track.vip/api/host/quote/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
host_session_id: hostSessionId,
pickup_candidate: pickupCandidate,
delivery_candidate: deliveryCandidate,
}),
});
const json = await res.json();
if (json.code !== 0) throw new Error(json.message);
if (json.data.status === "failed") throw new Error(json.data.error_message ?? "询价失败");
return json.data.quotes;
}
3. 统一响应格式
{ "code": 0, "message": "ok", "data": { } }
| 字段 | 说明 |
|---|---|
code |
0 成功;非 0 为错误码 |
message |
人类可读说明 |
data |
业务数据 |
4. 货物类型与限制
cargo_type 枚举:
general_freight · machinery · furniture · electronics · building_materials · auto_parts · food_nonperishable · apparel · other
| 项 | 限制 |
|---|---|
| 托盘数 | 1 – 25 |
| 单托重量 | 0.01 – 9,999 lb |
| 单托尺寸(换算英寸后) | 长 ≤ 999,宽 ≤ 99,高 ≤ 99 |
5. 自测方法
5.1 第一步:联想(PowerShell)
注意: Windows PowerShell 下
curl.exe -d '{...}'容易因引号转义导致 JSON 无效,返回请求体格式无效。请用 JSON 文件或 Invoke-RestMethod。
推荐:JSON 文件
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"
推荐:Invoke-RestMethod
$body = Get-Content "deploy/host-candidates-req.example.json" -Raw
Invoke-RestMethod -Uri "https://if.dev.51track.vip/api/host/quote/candidates" `
-Method POST -ContentType "application/json" -Body $body
成功标志:code: 0,且 data.host_session_id 存在。
5.2 第二步:取报价
从第一步响应中各取一条 selectable: true 的候选,构造 body 调用:
# 将 host_session_id、pickup_candidate、delivery_candidate 填入 body 后:
Invoke-RestMethod -Uri "https://if.dev.51track.vip/api/host/quote/submit" `
-Method POST -ContentType "application/json" -Body $submitJson
成功标志:data.status === "done",data.quotes 含 final_total。
5.3 Linux / macOS
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"
6. 方式 B:Token 三步接口
后期启用鉴权时,将 HOST_PUBLIC_API_ENABLED=false,改用以下流程。宿主须自行轮询。
6.1 鉴权
Authorization: Bearer <Service Token>
X-Customer-Id: <Customer ID>
Content-Type: application/json
6.2 流程
| 步骤 | 接口 | 说明 |
|---|---|---|
| 1 | POST /api/addresses/mothership-candidates |
仅地址,返回候选 |
| 2 | POST /api/quotes |
确认地址 + 货物,返回 quote_id + processing |
| 3 | GET /api/quotes/{quote_id} |
每 2 秒轮询,直到 done / failed |
第二步 body 须含 customer_id、request_id(UUID v4)、经 MotherShip 确认的地址字段(mothership_option_id、selected_from_mothership: true 等)及货物信息。
Token 由我方在 HOST_SERVICE_TOKENS 中配置后发放。
7. 错误码
方式 A 常见错误
| code | HTTP | 说明 | 处理 |
|---|---|---|---|
VALIDATION_FAILED |
400 | 参数无效 | 检查字段;message 为「请求体格式无效」时检查 JSON 格式 |
FORBIDDEN |
403 | 公开接口未启用 | 确认 HOST_PUBLIC_API_ENABLED=true |
SESSION_EXPIRED |
404 | 会话过期 | 重新调用第一步 |
ADDRESS_SESSION_MISMATCH |
400 | 候选与第一步不匹配 | 使用第一步返回的候选对象 |
ADDRESS_NOT_SELECTABLE |
400 | 选了不可用地址 | 换 selectable: true 的候选 |
QUOTE_TIMEOUT |
504 | 询价超时 | 稍后重试 |
RATE_LIMITED |
429 | 限流 | 降低频率 |
通用错误
| code | HTTP | 说明 |
|---|---|---|
UNAUTHORIZED |
401 | Token 无效(方式 B) |
INTERNAL_ERROR |
5xx | 服务异常 |
询价业务失败时 HTTP 可能仍为 200,data.status === "failed",见 error_message。
8. 安全与运维
- 方式 A 当前免 Token,仅建议在可信内网或已控域名下使用;上线前改方式 B。
- 方式 B 的 Token 仅放宿主服务端,禁止写进浏览器或公开仓库。
- 服务未开放 CORS;浏览器页请勿直接
fetch查价域名,应通过宿主后端或同域代理。 - 第二步网关/Nginx 须设
proxy_read_timeout 420s;。 - 报价有效期见
valid_until,过期需重新询价。
9. 联系与支持
| 事项 | 说明 |
|---|---|
| 开通 / 环境确认 | 联系查价系统管理员 |
| 接口故障 | 提供 host_session_id 或 quote_id、发生时间 |
| 文档版本 | 2026-06-30 |