Appearance
HTTP 请求 / 响应规范
适用于所有 /openapi/v1/* 接口。请求与响应风格全部接口统一,渠道按本规范实现一次即可适用所有接口,无需为每个接口定制解析逻辑。
一、请求
1.1 URL 与方法
| 项 | 约定 |
|---|---|
| Base URL | 沙箱 https://test-api.cxh.me / 生产 https://api.cxh.me |
| 路径前缀 | /openapi/v1/ |
| HTTP 方法 | 所有业务接口一律使用 POST(查询接口同样使用 POST) |
| Content-Type | application/json;charset=UTF-8 |
| 编码 | UTF-8 |
| Body 大小 | 不超过 1 MB |
查询接口的过滤条件以 JSON body 传递,不使用 query string;此约定使所有接口可统一应用幂等头部。
1.2 必传请求头
| Header | 必填 | 含义 / 示例 |
|---|---|---|
Content-Type | 是 | application/json;charset=UTF-8 |
X-CXH-App-Id | 是 | 渠道唯一标识,如 test_xxxxxxx |
X-CXH-Timestamp | 是 | 请求构造时刻的 Unix 毫秒数,如 1714003200123。与 CXH 时差超过 5 分钟将被拒(401003) |
X-CXH-Nonce | 是 | 32 位 hex 随机串,10 分钟内不可重复(401004) |
X-CXH-Request-Id | 是 | 渠道生成的请求追踪 ID,建议使用 UUID;同值会原样返回在响应中 |
X-CXH-Signature | 是 | HMAC-SHA256 base64 签名,详见 签名 + 字段加密 |
Authorization | 业务接口必填 | Bearer <accessToken>;auth/token 接口无需携带 |
Idempotency-Key | 写接口建议 | UUID;同 key 与不同 body 组合将触发 409001 |
签名头的拼装与 HMAC 计算公式见 签名 + 字段加密 § 1.1。
1.3 Body 字段类型约定
| 类型 | 序列化形式 | 说明 |
|---|---|---|
| 字符串 | JSON "..." | 默认明文;敏感字段需 AES 加密(详见 字段级加密) |
| 整数 | JSON 数字 / 字符串 | 所有 64 位整型 ID 字段(orderNo / userId / channelId 等)统一使用 JSON 字符串,以规避 JavaScript Number.MAX_SAFE_INTEGER(2^53) 精度限制 |
| 金额 | JSON 数字(整型) | 单位为分(cent),Long 类型;100 表示 1.00 元;不使用浮点 |
| 时间 | "yyyy-MM-dd HH:mm:ss" | UTC+8 时区;响应中所有时间字段一律此格式 |
| 布尔 | JSON true / false | — |
| 枚举 | 大写下划线字符串 | 如 BIND_SUCCESS / PAY_FAIL,完整取值见 字段约定 |
1.4 完整请求示例
POST /openapi/v1/auth/token(获取访问令牌,无需 Authorization):
http
POST /openapi/v1/auth/token HTTP/1.1
Host: test-api.cxh.me
Content-Type: application/json;charset=UTF-8
X-CXH-App-Id: test_xxxxxxx
X-CXH-Timestamp: 1714003200123
X-CXH-Nonce: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
X-CXH-Request-Id: 7f8a9b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c
X-CXH-Signature: ab12CDef34GHij56KLmn78OPqr90STuv...
Idempotency-Key: 7f8a9b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c
{"grantType":"client_credentials","appId":"test_xxxxxxx"}二、响应
2.1 HTTP 状态码
| 状态码 | 含义 |
|---|---|
200 | 业务成功与业务失败均使用 200,具体结果以响应 body 中的 code 字段为准 |
401 | 鉴权层错误(签名 / 时间戳 / nonce / accessToken 失效)。响应 body 仍遵循统一结构,code 形如 401xxx |
429 | 限流。响应 body 仍遵循统一结构,code 形如 429xxx |
5xx | CXH 异常,渠道应自动重试(指数退避,最多 3 次) |
渠道判断业务结果时应先核对 HTTP 状态码,200 时再核对 body 中
code == "0";此两层条件同时满足才表示业务成功。
2.2 Body 包装结构
所有响应 body 一律采用以下结构:
json
{
"code": "0",
"message": "success",
"data": { ... },
"requestId": "7f8a9b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c",
"timestamp": "2026-04-28 18:30:45",
"success": true
}| 字段 | 类型 | 说明 |
|---|---|---|
code | string | "0" 表示业务成功;非 "0" 表示业务失败,完整取值见 错误码 |
message | string | 人类可读描述;渠道仅用于日志与展示,不应基于此字段做分支判断 |
data | object | array | null | 业务数据;失败时为 null |
requestId | string | 与请求头 X-CXH-Request-Id 一致(便于日志关联);若请求未携带,由 CXH 生成 |
timestamp | string | CXH 生成响应的时间(yyyy-MM-dd HH:mm:ss,UTC+8) |
success | boolean | code == "0" 时为 true;为冗余字段,部分 SDK 用于快捷判断 |
2.3 成功响应示例
json
{
"code": "0",
"message": "success",
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
"expiresIn": "7200",
"expiresAt": "2026-04-28 20:30:45"
},
"requestId": "7f8a9b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c",
"timestamp": "2026-04-28 18:30:45",
"success": true
}2.4 失败响应示例
json
{
"code": "401002",
"message": "签名错误",
"data": null,
"requestId": "7f8a9b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c",
"timestamp": "2026-04-28 18:30:45",
"success": false
}完整业务失败码清单见 错误码。
2.5 渠道解析建议
python
resp = requests.post(url, headers=headers, json=body)
if resp.status_code >= 500:
# CXH 异常,应自动重试(指数退避)
retry_with_backoff()
elif resp.status_code != 200:
# 401 / 429 等鉴权或限流错误,根据 body 区分
payload = resp.json()
raise ApiError(payload['code'], payload['message'])
else:
payload = resp.json()
if payload['code'] != '0':
raise BusinessError(payload['code'], payload['message'])
data = payload['data'] # 业务成功,继续处理三、通用约定
3.1 幂等
- 所有写接口(
orders/create/agreements/bind-confirm/agreements/replace等)支持Idempotency-Key头幂等 - CXH 在 7 天内对同一
(appId, idempotencyKey)的请求返回首次响应 - 同 key + 同 body:直接返回首次响应(无副作用)
- 同 key + 异 body:返回
409001 IDEMPOTENCY_CONFLICT,渠道应排查请求构造逻辑 - 业务唯一约束(如
externalOrderNo)由 CXH 全局唯一性校验兜底,与头部幂等独立生效
3.2 请求追踪
- 渠道传入
X-CXH-Request-Id,CXH 日志全链路记录该 ID;问题排查时提供此 ID 可快速定位 CXH 侧日志 - 响应 body 中
requestId字段始终等于请求头X-CXH-Request-Id,可用于渠道侧日志关联 - 异常上报或客服工单建议附带此 ID
3.3 时区与时间格式
- 响应中所有时间字段一律为
yyyy-MM-dd HH:mm:ss格式,UTC+8(Asia/Shanghai) - 请求头
X-CXH-Timestamp为例外,使用 Unix 毫秒数(用于签名时差校验) - 渠道传入时间字符串时建议遵循同样格式;
2026-04-28T18:30:45+08:00等 ISO 8601 形式同样接受,响应统一转换为前者返回
3.4 ID 与金额精度
- 所有 64 位 ID(
orderNo/userId/channelId/paymentOrderNo等)以 JSON 字符串返回,渠道亦应以字符串接收与存储 - JavaScript 渠道应使用
String/BigInt处理,不应使用Number.parseInt,以免精度丢失 - 所有金额字段为
Long类型整型分,无浮点;100表示1.00元
3.5 重试与超时
| 场景 | 渠道建议 |
|---|---|
| HTTP 5xx | 指数退避重试 3 次(间隔 1s / 3s / 9s) |
HTTP 200 且 code=429xxx | 等待 1 分钟后再重试,不应立即重发 |
HTTP 200 且 code=0 | 业务成功,不应重试(避免重复创单) |
HTTP 200 且其他 code | 业务失败,应先依据 错误码 判断是否可重试,而非直接重试 |
| 网络超时 / 连接重置 | 使用同一 Idempotency-Key 重发,CXH 返回首次结果 |
建议请求超时配置:connect 5s / read 15s。
3.6 字段大小限制
| 项 | 上限 |
|---|---|
| 单个字符串字段 | 1024 字符(接口文档另有说明者除外) |
| 整个 JSON body | 1 MB |
| 单次列表查询返回 | 100 条(超出请使用分页参数 page / size) |