开放 API 对接指南
签名鉴权、幂等建单、按 Key 限流与出站回调。本页口径与 docs/04-API-DESIGN.md §4(真源 OPENAPI_CONTRACT.md v1.0)一致;机器面 GET /api/open/docs 上线后两处同源。
上手
对接四步
按这四步走通,再上生产。
- 01联系中文客服申请 API Key(f8ok_ 前缀,明文只在建钥/换钥响应中出现一次);写端点需运营显式开通 write 作用域。
- 02按 §鉴权 拼五段签名串,每个请求带齐 x-f8-key-id / x-f8-timestamp / x-f8-nonce / x-f8-signature 四个头。
- 03用 GET 端点(inventory / lots / tracking / billing)打通只读链路,再接 POST 建单(inbounds / outbounds,必带 Idempotency-Key)。
- 04上生产前按「限流、幂等与错误码」逐条核对退避与重试策略,出站回调按需向运营登记。
鉴权
凭据与签名
每个请求都要带四个签名头;签名串五段、顺序固定、换行分隔。
凭据格式
f8ok_<keyId>_<secret>(keyId 12 位 hex,secret 64 位 hex,字母表锁 hex)
签名算法
HMAC-SHA256 / base64url
时间窗
±5 分钟(300000ms,超窗 401 timestamp_out_of_window)
重放窗口
24 小时(nonce 去重)
并行可用钥
最多 2 把(active + grace 合计)
轮换宽限
24 小时(不可叠加;宽限届满即 expired)
默认作用域
read(写端点需运营开通 write)
状态机
active → grace → expired;任一状态可即时吊销 → revoked
签名串的拼法(LF = 换行符)
METHOD(大写)
LF
pathWithQuery(查询串原文,不重排不解码)
LF
timestamp(毫秒)
LF
nonce(每请求唯一)
LF
sha256Hex(请求体原文;空体也取 sha256("") 摘要)| 请求头 | 必填 | 说明 |
|---|---|---|
| x-f8-key-id | 是 | apiKey 第二段 keyId |
| x-f8-timestamp | 是 | 毫秒级 Unix 时间戳字符串 |
| x-f8-nonce | 是 | 每请求唯一随机串(建议 UUID 或 ≥16 位 base36) |
| x-f8-signature | 是 | 签名串的 HMAC-SHA256,base64url 输出 |
租户不可自证:customerCode 由鉴权层按 keyId 反查注入,请求体与查询串里的同名字段一律忽略。校验链固定:头齐备 → 时间窗 → keyId 存在 → 钥状态 → 可解密 → 签名比对 → nonce 去重 → 频控 → 作用域。
配额
限流、幂等与分页
超限返回 429 并带 Retry-After;幂等防「重签再建一张单」,与防重放是两把闸。
每 Key 默认限流
120 次 / 60 秒(固定窗按 epoch 分钟对齐)
按 Key 可调
运营可按 Key 覆写每分钟配额
幂等头
Idempotency-Key(客户端 UUID,≤64 字符)
幂等保留
24 小时;台账按「一把 Key」隔离
在途可重抢
占位超 5 分钟可被同键重抢;处理器抛错当场释放
分页默认/上限
pageSize 20 / 100;越界 400 invalid_pagination,不静默钳制
单张建单行数
skuLines 1..500
响应头
X-RateLimit-Limit / Remaining / Reset;429 时另带 Retry-After;恒 Cache-Control: no-store
通用响应固定 data + pagination{page,pageSize,total} + requestId;时间 ISO-8601 UTC 带毫秒;金额两位小数、币种恒 GBP。幂等命中也落审计;台账不可用时返回 503 idempotency_unavailable 且本次不执行。
端点
六个端点
六端点注册表;版本在路径(v1 → v2 发布后 v1 保留 6 个月)。库存调整、盘点、账户充值与面单二进制流不开放。
| 路径 | 方法 | 作用域 | 幂等键 | 说明 |
|---|---|---|---|---|
| /api/open/v1/inbounds | POST | write | 必带 | 入库预报建单,等价门户预报表单 |
| /api/open/v1/outbounds | POST | write | 必带 | 出库下单,只接 skuLines 与收件信息,不参与定价 |
| /api/open/v1/inventory | GET | read | 不适用 | 余额按 SKU/库位分页,含 7+2 桶全列 |
| /api/open/v1/lots | GET | read | 不适用 | 批次与效期,FEFO 可查 |
| /api/open/v1/tracking | GET | read | 不适用 | 出库单 + 轨迹事件流 trackingEvents |
| /api/open/v1/billing | GET | read | 不适用 | 账单与费用行,只读不含支付动作 |
示例
请求与响应
以入库预报建单为例(201 成功回执)。
POST /api/open/v1/inbounds(头 Idempotency-Key: <uuid>)
{
"contact": "王磊", "phone": "+8613800000000", "eta": "2026-11-04", "transport": "快递",
"platform": "AMZ", "tracking": "SF1234567890", "service": "FBA 转运", "attribute": "普货",
"productName": "蓝牙耳机、手机壳",
"skuLines": [
{ "skuCode": "SKU-001", "productName": "蓝牙耳机黑色款", "expectedQty": 120, "cartonCount": 4 },
{ "skuCode": "SKU-002", "productName": "手机壳透明款", "expectedQty": 300, "cartonCount": 2 }
]
}201 响应
{
"data": { "id": "IB-261028-0007", "status": "pending_review", "cartons": 6, "skuCount": 2,
"createdAt": "2026-10-28T02:40:11.004Z" },
"requestId": "6f0c3a1e-9b47-4d2a-8c1e-2f7a5b3d9c04"
}排错
错误码
错误体为扁平形状 {error, code, requestId}(对外契约,不套内部嵌套包络)。
| HTTP | code | 处置建议 |
|---|---|---|
| 401 | missing_signature_headers | 检查 SDK 是否漏带头(尤其反向代理剥头) |
| 401 | timestamp_out_of_window | 校正时钟;不要用缓存时间戳重发旧请求 |
| 401 | unknown_key_id | 核对 apiKey 前缀与签发环境(测试/生产不同库) |
| 401 | signature_mismatch | 核对五段顺序、path 与查询串原文、请求体原文、方法大小写 |
| 403 | key_revoked | 用剩余钥或申请重签,勿重试 |
| 403 | key_expired | 切到新钥;旧钥不再可用 |
| 403 | key_unusable | 服务端主密钥已变更 → 联系运营重签(一次性事件,不重试) |
| 403 | nonce_replayed | 每请求生成新 nonce,重试要重新签名 |
| 403 | scope_not_granted | 走运营开通 write 白名单 |
| 429 | rate_limited | 按 retryAfterMs 退避,勿并行重试 |
回调
出站 webhook
方向相反、算法相同:仓库主动把单据状态变化推给您,用同一条五段签名串验真(每端点独立 f8wh_ 密钥)。
每客户端点上限
3 个
尝试次数
6 次(退避 1 / 5 / 15 / 60 / 240 / 240 分钟)
投递超时
8 秒;4xx(除 408/429)判 blocked 不再重试
台账保留
7 天、上限 1000 行;at-least-once 语义,按 x-f8-event-id 幂等消费
| 回调头 | 说明 |
|---|---|
| x-f8-key-id | 回调端点编号(wh_xxxxxxxx,不是 API Key 编号) |
| x-f8-timestamp | 本次尝试的毫秒时间戳(每次重试重新签) |
| x-f8-nonce | 本次尝试随机串;接收端去重请按 x-f8-event-id,不要按 nonce 拦重试 |
| x-f8-signature | HMAC-SHA256(webhook_secret, 签名串) 的 base64url |
| x-f8-event-id | 事件号=幂等键 outbound:<单号>:<日志号> / inbound:<单号>:<日志号> |
| x-f8-attempt | 第几次尝试(1 起) |
| 事件类型 | 触发口径 |
|---|---|
| inbound.status_changed | 入库单状态变化(events 时间线,不截断) |
| outbound.status_changed | 出库单状态变化(operationLogs,保留最近 60 条) |
| outbound.backorder_split | 欠补拆单事实 |
| outbound.backorder_recheck | 到货复检结果 |
| outbound.intercept_completed | 截单完成事实 |
| test.delivery | 运营点「测试」的手握事件,不参与订阅 |
push 只说「变了」,pull 才是事实源:轨迹与作业明细请回查 GET /api/open/v1/tracking。作业粒度日志(scan_*、exception_* 等)不推。
开始对接
密钥申请与 write 作用域开通,由运营按客户档案办理。
提交公司 / 店铺信息与对接场景,客服会签发首把 Key 并同步契约版本口径(v1.0,破坏性变更走 /api/open/v2)。
