diff --git a/ymt_v3_api/refine.md b/ymt_v3_api/refine.md new file mode 100644 index 0000000..60f7f39 --- /dev/null +++ b/ymt_v3_api/refine.md @@ -0,0 +1,348 @@ +文档类型:调用文档 + +## 接口列表 + +### 1. 获取券码 +- **请求方式**:POST +- **Content-Type**:application/json +- **请求路由**:/openapi/v1/key/order + +#### 业务请求参数(明文,加密前) +| 字段名称 | 类型 | 描述 | 是否必填 | 示例值 | +|----------|------|------|----------|--------| +| out_biz_no | string | 外部业务号,幂等 | M | 123456 | +| activity_no | string | 活动编号 | M | ACT20260622001 | +| account | string | 账号,按活动类型透传 | N | 18666666666 | +| notify_url | string | 回调通知地址 | N | https://notify.example.com/openapi | + +#### 业务响应参数(解密后) +| 字段名称 | 类型 | 是否必填 | 描述 | +|----------|------|----------|------| +| out_biz_no | string | M | 外部业务号 | +| trade_no | string | M | 交易号 | +| key | string | N | 卡密 | +| url | string | N | 链接型活动返回短链接,key/url 不会同时为空 | +| valid_begin_time | string | N | 生效时间 | +| valid_end_time | string | N | 失效时间 | +| usable_num | uint32 | M | 可用次数 | +| usage_num | uint32 | M | 已使用次数 | +| status | uint32 | M | 状态:1 正常,2 已核销,3 已作废 | +| settlement_price | float | N | 结算价 | +| account | string | N | 上报账号 | + +#### 请求示例 +明文业务参数: +```json +{ + "out_biz_no": "order_001", + "activity_no": "ACT20260622001", + "account": "18666666666", + "notify_url": "https://notify.example.com/openapi" +} +``` +请求体示例: +```json +{ + "ciphertext": "加密后的业务报文" +} +``` + +#### 响应示例 +异常: +```json +{ + "code": 401, + "message": "Signature verification failed", + "reason": "INVALID_SIGNATURE" +} +``` +成功: +```json +{ + "code": 200, + "data": { + "ciphertext": "加密后的响应报文" + }, + "message": "成功" +} +``` +解密后示例: +```json +{ + "out_biz_no": "order_001", + "trade_no": "7251449503000383488", + "key": "aZKdU9BymzR6qGRzJM", + "url": "", + "valid_begin_time": "2026-06-22 15:30:00", + "valid_end_time": "2026-12-31 23:59:59", + "usable_num": 1, + "usage_num": 0, + "status": 1, + "settlement_price": 9.9, + "account": "18666666666" +} +``` + +### 2. 券码查询 +- **请求方式**:POST +- **Content-Type**:application/json +- **请求路由**:/openapi/v1/key/query + +#### 业务请求参数 +| 字段名称 | 类型 | 描述 | 是否必填 | 示例值 | +|----------|------|------|----------|--------| +| out_biz_no | string | 外部业务号,与 trade_no 二选一 | N | order_001 | +| trade_no | string | 交易号,与 out_biz_no 二选一 | N | 7251449503000383488 | + +#### 业务响应参数 +与“获取券码”响应参数一致。 + +#### 响应示例 +```json +{ + "code": 200, + "data": { + "out_biz_no": "order_001", + "trade_no": "7251449503000383488", + "key": "aZKdU9BymzR6qGRzJM", + "url": "", + "valid_begin_time": "2026-06-22 15:30:00", + "valid_end_time": "2026-12-31 23:59:59", + "usable_num": 1, + "usage_num": 0, + "status": 1, + "settlement_price": 9.9, + "account": "18666666666", + "ciphertext": "" + }, + "message": "成功" +} +``` + +### 3. 券码作废 +- **请求方式**:POST +- **Content-Type**:application/json +- **请求路由**:/openapi/v1/key/discard + +#### 业务请求参数 +| 字段名称 | 类型 | 描述 | 是否必填 | 示例值 | +|----------|------|------|----------|--------| +| out_biz_no | string | 外部业务号,与 trade_no 二选一 | N | order_001 | +| trade_no | string | 交易号,与 out_biz_no 二选一 | N | 7251449503000383488 | + +#### 业务响应参数 +| 字段名称 | 类型 | 是否必填 | 描述 | +|----------|------|----------|------| +| out_biz_no | string | M | 外部业务号 | +| trade_no | string | M | 交易号 | +| status | uint32 | M | 3 表示已作废 | + +#### 响应示例 +```json +{ + "code": 200, + "data": { + "out_biz_no": "order_001", + "trade_no": "7251449503000383488", + "status": 3, + "ciphertext": "" + }, + "message": "成功" +} +``` + +### 4. 批量发卡 +- **请求方式**:POST +- **Content-Type**:application/json +- **请求路由**:/openapi/v1/key/batch_order + +#### 业务请求参数 +| 字段名称 | 类型 | 描述 | 是否必填 | 示例值 | +|----------|------|------|----------|--------| +| out_biz_no | string | 外部业务号,幂等 | M | batch_001 | +| activity_no | string | 活动编号 | M | ACT20260622001 | +| number | int32 | 发卡数量 | M | 100 | +| notify_url | string | 回调通知地址 | N | https://notify.example.com/openapi | + +#### 业务响应参数 +| 字段名称 | 类型 | 是否必填 | 描述 | +|----------|------|----------|------| +| out_biz_no | string | M | 外部业务号 | +| trade_no | string | M | 交易号 | +| status | string | M | 任务状态,初始返回 processing | + +#### 响应示例 +成功: +```json +{ + "code": 200, + "data": { + "ciphertext": "加密后的响应报文" + }, + "message": "成功" +} +``` +解密后示例: +```json +{ + "out_biz_no": "batch_001", + "trade_no": "7251449503000383499", + "status": "processing" +} +``` + +### 5. 批量查询 +- **请求方式**:POST +- **Content-Type**:application/json +- **请求路由**:/openapi/v1/key/batch_query + +#### 业务请求参数 +| 字段名称 | 类型 | 描述 | 是否必填 | 示例值 | +|----------|------|------|----------|--------| +| out_biz_no | string | 外部业务号,与 trade_no 二选一 | N | batch_001 | +| trade_no | string | 交易号,与 out_biz_no 二选一 | N | 7251449503000383499 | + +#### 业务响应参数 +| 字段名称 | 类型 | 是否必填 | 描述 | +|----------|------|----------|------| +| out_biz_no | string | M | 外部业务号 | +| trade_no | string | M | 交易号 | +| status | string | M | processing / success / failed | +| download_url | string | N | 批量任务成功后返回下载地址 | +| zip_password | string | N | 批量任务成功后返回压缩包密码 | + +#### 响应示例 +成功: +```json +{ + "code": 200, + "data": { + "ciphertext": "加密后的响应报文" + }, + "message": "成功" +} +``` +解密后示例: +```json +{ + "out_biz_no": "batch_001", + "trade_no": "7251449503000383499", + "status": "success", + "download_url": "https://oss.example.com/openapi_7251449503000383499.zip", + "zip_password": "123456" +} +``` + +## 认证/加密/签名 + +### 环境配置 +- 测试环境地址:https://gateway.dev.cdlsxd.cn +- 正式环境地址:https://market.api.86698.cn +- 测试参数: + - app_id: "xxx" + - private_key: "xxx" (应用客户私钥,用于请求签名) + - public_key: "xxx" (应用平台公钥,用于平台响应或回调验签) + - key: "xxxx" (业务参数加密key) + - activity_no: "xxxx" + - sign_type: "RSA" + +### 请求模式 +统一采用 Header 鉴权模式: +- Header 传:Appid、Timestamp、Sign +- Body 传:ciphertext + +### 公共 Header 请求参数 +| 字段名称 | 类型 | 描述 | 示例值 | +|----------|------|------|--------| +| Appid | string | 分配给开发者的应用 ID | 123456 | +| Timestamp | string | 发送请求的时间,格式 yyyy-MM-dd HH:mm:ss | 2026-06-22 15:30:00 | +| Sign | string | 请求签名串 | 详见 SDK 示例 | +| Content-Type | string | 请求数据格式 | application/json | + +示例: +```json +{ + "Sign": ["签名字符串"], + "Appid": ["应用ID"], + "Timestamp": ["请求时间"], + "Content-Type": ["application/json"] +} +``` + +### 公共请求参数 +| 字段名称 | 类型 | 描述 | 示例值 | +|----------|------|------|--------| +| ciphertext | string | 请求业务参数加密串 | 详见 SDK 示例 | + +示例: +```json +{ + "ciphertext": "加密后的业务报文" +} +``` + +### 公共响应参数 +| 字段名称 | 类型 | 描述 | +|----------|------|------| +| code | int32 | 200 成功 | +| message | string | 请求描述 | +| reason | string | 错误原因,错误时返回 | +| data.ciphertext | string | 业务响应加密串 | + +### 业务参数加密规则 +1. 将业务参数去掉“零”值的参数(值为0或空字符串等),再由小到大按照字母排序,转成JSON字符串得到 plaintext。 +2. 使用应用 key 将 plaintext 字符串加密,加密方式为 AES(ECB模式) 或 SM4(CBC模式),得到加密业务参数 ciphertext。 + +### 签名规则 +1. 拼接签名字符串:`app_id + timestamp + ciphertext`(分配给开发者的应用ID + 发送请求的时间 + 加密业务参数)。 +2. 使用应用私钥(private_key)对签名字符串进行签名,生成 Sign。 + +### 响应解密 +响应中的 `data.ciphertext` 使用与请求相同的加密方式和 key 进行解密,得到业务响应明文。 + +### 回调验签 +1. 获取 header 头里面的签名信息。 +2. 获取 body 里面的业务参数 data。 +3. 将业务参数 data 去掉“零”值的参数,再由小到大按照字母排序,转成JSON字符串得到 plaintext。 +4. 使用应用 key 将 plaintext 字符串加密(AES/SM4)得到 ciphertext。 +5. 拼接签名字符串:`app_id + timestamp + ciphertext`。 +6. 使用应用公钥(public_key)验签。 + +### 时间戳规则 +- 时间格式:yyyy-MM-dd HH:mm:ss +- 请求时间与服务端时间误差不能超过 3 分钟。 + +### SDK 参考 +- Go: https://gitee.com/chengdu_blue_brothers/ymt-openapi-go-sdk.git +- Java: https://codeup.aliyun.com/lsxd/marketing/ymt-openapi-java-sdk.git + +## 错误码 + +### 公共错误码 +| code状态码 | reason | 错误原因 | 解决 | +|------------|--------|----------|------| +| 500 | PANIC/其它 | 系统错误 | 联系平台处理 | +| 400 | INVALID_PAYLOAD | 请求外壳格式错误 | 请检查请求 JSON 结构 | +| 400 | MISSING_PARAM | 缺少必要参数 | 请检查 app_id、timestamp、sign、ciphertext | +| 400 | INVALID_TIMESTAMP | 时间格式错误 | 请检查时间格式 | +| 400 | DECRYPT_FAILED | 业务参数解密失败 | 请检查加密方式与密钥 | +| 401 | APP_NOT_FOUND | 应用不存在 | 请检查应用 ID | +| 401 | INVALID_SIGNATURE | 签名错误 | 请检查签名串与私钥 | +| 401 | EXPIRED_TIMESTAMP | 请求已过期 | 请检查客户端时间 | +| 429 | DUPLICATE_REQUEST | 重复请求,请稍后重试 | 请避免短时间内重复提交同一业务号 | + +### 业务错误码 +| code状态码 | reason | 错误原因 | 解决 | +|------------|--------|----------|------| +| 401 | ACTIVITY_NOT_AUTH | 活动未授权 | 请检查活动授权状态 | +| 401 | MERCHANT_NOT_EXIST | 客户不存在 | 请检查客户是否存在 | +| 401 | MERCHANT_NOT_AUTH | 客户冻结 | 请检查客户授权状态 | +| 401 | MERCHANT_APP_INCOMPLETE | 客户应用配置未完善 | 请检查客户应用配置 | +| 401 | MERCHANT_APP_NOT_AUTH | 应用不存在或未授权 | 请检查客户应用授权状态 | +| 403 | ACTIVITY_EXPIRE | 活动已结束 | 请检查活动是否有效 | +| 403 | ACTIVITY_OUT_OF_STOCK | 活动剩余量不足 | 请检查活动库存 | +| 404 | ACTIVITY_NOT_EXIST | 活动不存在 | 请检查活动编号 | +| 404 | MERCHANT_ORDER_NOT_EXIST | 订单不存在 | 请检查交易号或外部业务号 | +| 404 | KEY_NOT_EXIST | key码不存在 | 请检查订单信息 | +| 400 | PARAM_FAIL | 参数错误 | 请检查业务参数 | +| 400 | PARAM_DECRYPT_FAIL | 明文参数格式错误 | 请检查密文解密后的业务报文 | \ No newline at end of file