增加91卡券订单示例

This commit is contained in:
yml
2026-05-04 21:32:12 +08:00
parent 1b0a51b0bd
commit f4cc2ce623
9 changed files with 909 additions and 272 deletions
+6
View File
@@ -0,0 +1,6 @@
# 本文档仅做示例说明,接口路径、签名规则、参数字段、入参格式等,可自定义。
#
# 注意,本业务对接非代码开发级别的对接,内部集成了模块人工参数配置实现的。部分特殊场景有所限制,主要涉及特殊的算法不支持、部分参数不支持传递等。
# 可以先编写好接口文档提供给客服,有问题客服会联系你哈
+45
View File
@@ -0,0 +1,45 @@
# 签名计算规则示例:
# 以下仅做示例说明,实际的签名规则可自行设计。
### 简要描述:
- 除sign字段外,所有参数按照字段名的ascii码从小到大排序后,使用QueryString的格式(即key1=value1&key2=value2…)拼接成字符串后,再在前后追加上 商户密钥 的值,然后转换成32位大写的MD5字符串。
#### <font color='red'>注意事项:如空值参数是否参与签名需要在提供的文档中进行说明哈</font>
**假设 商户密钥 值为:** <font color='red'>rste57w8rsubsnxsb384ur3u9kn5fzhr0a091b3aa4324435aab703142518a8f7</font>
**假设请求参数为:**
```csharp
{
"userId":"1001",
"orderNo":"2023061917481700001",
"productNo":"test01",
"buyNum":1,
"attach":"{\"account\":\"13888888888\"}",
"maxAmount":""
"timestamp":1687168097,
"callbackUrl":"",
"version":"1.0",
"sign":"EF387ED4D401A275498A9FCC6C22116B"
}
```
**验签步骤:**
1. 转换成字符串如下:
```
attach={"account":"13888888888"}&buyNum=1&callbackUrl=&maxAmount=&orderNo=2023061917481700001&productNo=test01&timestamp=1687168097&userId=1001&version=1.0
```
2. 前后追加上 商户密钥 的MD5源串如下:
```
rste57w8rsubsnxsb384ur3u9kn5fzhr0a091b3aa4324435aab703142518a8f7attach={"account":"13888888888"}&buyNum=1&callbackUrl=&maxAmount=&orderNo=2023061917481700001&productNo=test01&timestamp=1687168097&userId=1001&version=1.0rste57w8rsubsnxsb384ur3u9kn5fzhr0a091b3aa4324435aab703142518a8f7
```
3. MD5后转成32位大写的签名值如下:
```
EF387ED4D401A275498A9FCC6C22116B
```
+154
View File
@@ -0,0 +1,154 @@
# 91卡券异步卡密下单接口
## 1. 接口说明
本文档为当前项目对接 `91卡券` 的正式技术文档,用于提交客服审核。
本项目对接场景说明:
- `91卡券` 负责售卖与自动发货;
- 我方系统负责接收订单、创建任务、生成领取链接;
- 该领取链接会在后续查询订单接口中,作为最终卡密内容返回给 `91卡券`
- `91卡券` 再将该链接自动发给买家。
注意:
- 本接口为**异步卡密下单接口**
- 首次下单成功受理后,返回 `orderStatus = 10`
- **不会**在该接口首次响应中直接返回最终领取链接;
- 最终链接请通过“查询订单接口”获取。
## 2. 请求方向
- `91卡券平台 -> 接入方系统`
## 3. 请求 URL
请按以下地址配置:
```text
POST https://221329.cc.cd/api/v1/open/91/orders/create
```
## 4. 请求方式
- `POST`
- `Content-Type: application/json;charset=utf-8`
## 5. 签名规则
签名规则采用 签名规则示例 中的约定:
-`sign` 外,所有参数按字段名 ASCII 升序排序;
- 使用 `key=value&key=value` 方式拼接;
- 前后拼接商户密钥;
-`MD5`,输出 32 位大写字符串;
- 空值参数参与签名。
## 6. 请求参数
| 参数名 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | 是 | string | 商家订单号,唯一,用于幂等处理。 |
| `productNo` | 是 | string | 接入方商品编号。建议与我方内部履约 SKU 一一对应。 |
| `buyNum` | 是 | int | 购买数量。 |
| `maxAmount` | 否 | string | 商家可接受最大成本金额。值为整单金额,非单价。若传值,则我方按该金额校验,超出时返回失败。 |
| `callbackUrl` | 否 | string | 由 `91卡券` 提供的回调地址。当前项目可接收但不依赖该字段完成主流程。 |
| `timestamp` | 是 | long | 10 位秒级 Unix 时间戳,用于请求时效校验。 |
| `version` | 是 | string | 固定传 `1.0`。 |
| `sign` | 是 | string | 签名。 |
## 7. 请求示例
```json
{
"orderNo": "P91KS202605040001",
"productNo": "KS-CLOUD-SKU-001",
"buyNum": 1,
"maxAmount": "0.0000",
"callbackUrl": "https://cb.example.com/notify/91/order",
"timestamp": 1777867200,
"version": "1.0",
"sign": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```
## 8. MD5 源串示例
假设:
- `userId = 1001`
- 商户密钥为:`your_secret_key`
则源串示例如下:
```text
your_secret_keybuyNum=1&callbackUrl=https://cb.example.com/notify/91/order&maxAmount=0.0000&orderNo=P91KS202605040001&productNo=KS-CLOUD-SKU-001&timestamp=1777867200&userId=1001&version=1.0your_secret_key
```
## 9. 业务处理规则
我方系统收到请求后,按以下规则处理:
1. 校验签名与时间戳;
2.`orderNo` 做幂等;
3. 校验 `productNo` 是否已映射到当前项目的快手履约商品;
4. 若传入 `maxAmount`,则校验成本是否超限;
5. 创建内部订单;
6. 创建快手 Cloud 履约任务;
7. 生成当前项目领取链接,例如:`https://221329.cc.cd/#/claim/{token}`
8. 首次响应返回处理中状态,由 `91卡券` 后续调用查询订单接口获取最终卡密内容。
## 10. 响应参数
| 参数名 | 类型 | 必须返回 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | string | 必须返回 | 商家订单号,来源 `91卡券` 下单请求。 |
| `outTradeNo` | string | 成功时必须 | 我方系统内部订单号。 |
| `orderStatus` | int | 成功时必须 | 订单状态。`10`:处理中;`30`:失败。<br>注意:当前接口为异步商品下单接口,首次响应**不会返回 `20`**。 |
| `orderCost` | decimal(14,4) | 成功时可返回 | 订单总成本,单位:元。若当前阶段无法确认,可返回 `0.0000`。 |
| `cards` | string | 非必须 | 当前阶段建议返回空字符串。最终卡密内容请在查询订单接口中返回。 |
| `failCode` | int | 失败时可返回 | 失败代码。 |
| `failReason` | string | 失败时可返回 | 失败原因。 |
## 11. 响应示例
### 11.1 受理成功
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 10,
"orderCost": 0.0000,
"cards": ""
}
}
```
### 11.2 下单失败
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "",
"orderStatus": 30,
"failCode": 1220,
"failReason": "订单成本超出可接受范围"
}
}
```
## 12. 对接说明
- `productNo` 请按我方提供的商品编号配置;
- 本接口成功受理后,不代表最终卡密已可交付;
- 最终交付内容为我方系统生成的领取链接,链接域名固定为 `221329.cc.cd`
- 该链接将在“查询订单接口”中,通过 `cards` 加密串返回;
- 建议 `91卡券` 将此商品配置为:`异步卡密商品`
+203
View File
@@ -0,0 +1,203 @@
# 91卡券查询订单接口
## 1. 接口说明
本文档为当前项目对接 `91卡券` 的正式技术文档,用于提交客服审核。
本接口用于在异步卡密下单后,由 `91卡券` 主动查询订单状态与最终卡密内容。
当前项目的最终交付物不是传统卡号密码,而是:
- 我方系统生成的**领取链接**
- 该链接将作为最终卡密内容,通过 `cards` 字段返回给 `91卡券`
- `91卡券` 再使用自动发货能力,将该领取链接展示给买家。
## 2. 请求方向
- `91卡券平台 -> 接入方系统`
## 3. 请求 URL
请按以下地址配置:
```text
POST https://221329.cc.cd/api/v1/open/91/orders/query
```
## 4. 请求方式
- `POST`
- `Content-Type: application/json;charset=utf-8`
## 5. 签名规则
签名规则采用 2.签名规则示例 中的约定:
-`sign` 外,所有参数按字段名 ASCII 升序排序;
- 使用 `key=value&key=value` 方式拼接;
- 前后拼接商户密钥;
-`MD5`,输出 32 位大写字符串;
- 空值参数参与签名。
## 6. 请求参数
| 参数名 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | 是 | string | 商家订单号。 |
| `timestamp` | 是 | long | 10 位秒级 Unix 时间戳,用于请求时效校验。 |
| `version` | 是 | string | 固定传 `1.0`。 |
| `sign` | 是 | string | 签名。 |
## 7. 请求示例
```json
{
"orderNo": "P91KS202605040001",
"timestamp": 1777867260,
"version": "1.0",
"sign": "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
}
```
## 8. MD5 源串示例
假设:
- `userId = 1001`
- 商户密钥为:`your_secret_key`
则源串示例如下:
```text
your_secret_keyorderNo=P91KS202605040001&timestamp=1777867260&userId=1001&version=1.0your_secret_key
```
## 9. 业务处理规则
我方系统收到查询请求后,按以下规则返回:
1. 校验签名与时间戳;
2. 根据 `orderNo` 查询内部订单;
3. 若订单存在但领取链接尚未准备完成,返回 `orderStatus = 10`
4. 若领取链接已生成,可交付,返回 `orderStatus = 20`
5. 若订单无法履约,返回 `orderStatus = 30`
6. 当返回 `20` 时,通过 `cards` 返回最终卡密内容。
## 10. 响应参数
| 参数名 | 类型 | 必须返回 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | string | 必须返回 | 商家订单号,来源 `91卡券` 下单请求。 |
| `outTradeNo` | string | 必须返回 | 我方系统内部订单号。 |
| `orderStatus` | int | 必须返回 | 订单状态。`10`:处理中;`20`:成功;`30`:失败。 |
| `failCode` | int | 失败时建议返回 | 失败代码。可以不返回该字段,但不要返回 `null`。 |
| `failReason` | string | 失败时建议返回 | 失败原因。 |
| `orderCost` | decimal(14,4) | 成功时建议返回 | 订单总成本,单位:元。 |
| `cards` | string | `orderStatus = 20` 时必须 | 卡密数据加密串。当前项目通过该字段返回领取链接。 |
| `cards[0].cardNo` | string | 成功时必须 | 最终交付的领取链接,格式为 `https://221329.cc.cd/#/claim/{token}`。 |
| `cards[0].cardPwd` | string | 可选 | 当前场景固定为空字符串。 |
| `cards[0].expireTime` | string | 可选 | 领取链接过期时间,支持 `yyyy-MM-dd HH:mm:ss` 或 10 位秒级 Unix 时间戳。 |
| `cards[0].jumpLink` | string | 可选 | 与 `cardNo` 保持一致,用于兼容链接展示场景。 |
## 11. cards 原始结构约定
由于已确认允许将链接作为最终卡密内容展示给买家,当前项目约定:
- `cardNo`:直接放领取链接;
- `cardPwd`:留空;
- `expireTime`:放领取链接过期时间;
- `jumpLink`:与 `cardNo` 一致。
原始结构示例如下:
```json
[
{
"cardNo": "https://221329.cc.cd/#/claim/abc123xyz",
"cardPwd": "",
"expireTime": "2026-05-05 12:00:00",
"jumpLink": "https://221329.cc.cd/#/claim/abc123xyz"
}
]
```
`buyNum > 1`,则 `cards` 原始结构中返回多个卡项,每个卡项对应一个独立领取链接。
## 12. 响应示例
### 12.1 处理中
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 10,
"failCode": 0,
"failReason": "",
"orderCost": 0.0000,
"cards": ""
}
}
```
### 12.2 查询成功
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 20,
"failCode": 0,
"failReason": "",
"orderCost": 0.0000,
"cards": "加密后的cards字符串"
}
}
```
`cards` 解密前原始结构示例:
```json
[
{
"cardNo": "https://221329.cc.cd/#/claim/abc123xyz",
"cardPwd": "",
"expireTime": "2026-05-05 12:00:00",
"jumpLink": "https://221329.cc.cd/#/claim/abc123xyz"
}
]
```
### 12.3 查询失败
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 30,
"failCode": 1204,
"failReason": "商品未配置或订单无法履约"
}
}
```
## 13. 对接说明
- 本接口是 `91卡券` 自动发货的关键接口;
- 当返回 `orderStatus = 20` 时,表示我方已准备好最终交付内容;
- 最终交付内容是领取链接,不是传统卡号密码;
- 领取链接域名固定为 `221329.cc.cd`
- 买家收到链接后,会进入我方系统领取页完成后续快手核销与履约流程;
- 建议 `91卡券` 侧确认:
- `cards.cardNo` 可直接展示完整链接;
- `jumpLink` 可按链接字段兼容展示;
- 查询频率按异步商品标准轮询配置。
+315
View File
@@ -0,0 +1,315 @@
# 91卡券接入当前项目接口配置
## 1. 对接目标
- `91卡券` 作为外部售卖与自动发货通道。
- 当前项目负责:
- 接收 `91卡券` 下单请求;
- 在系统内生成订单与快手履约任务;
- 生成当前项目自己的领取链接;
-`91卡券` 通过自动发货,将该领取链接展示给买家。
- 已确认:**允许将链接作为最终卡密内容展示给买家**。
## 2. 对接结论
本次对接不走 `Agiso/咸鱼` 的站内消息链路,而是走:
1. `91卡券` 调用我方异步下单接口;
2. 我方创建内部订单,并生成领取链接;
3. `91卡券` 调用我方查询订单接口;
4. 我方在查询结果的 `cards` 中返回领取链接;
5. `91卡券` 自动发货给买家。
## 3. 接口地址建议
基础前缀建议:
```text
https://你的域名/api/v1/open/91
```
接口列表:
- 异步卡密下单:`POST /api/v1/open/91/orders/create`
- 查询订单接口:`POST /api/v1/open/91/orders/query`
## 4. 签名配置
签名规则采用当前文档里的示例规则:
-`sign` 外,所有参数按字段名 ASCII 升序排序;
- 使用 `key=value&key=value` 方式拼接;
- 前后拼接商户密钥;
-`MD5`,输出 32 位大写字符串。
建议固定配置:
- `signType`: `MD5`
- `charset`: `UTF-8`
- `timestamp`: 10 位秒级 Unix 时间戳
- `version`: `1.0`
- 空值参数是否参与签名:`参与`
## 5. 业务字段映射
### 5.1 下单请求 -> 当前项目
| 91字段 | 当前项目用途 | 说明 |
| --- | --- | --- |
| `orderNo` | 外部订单号 / 幂等键 | 建议映射为内部 `platformOrderId` |
| `productNo` | 商品映射 | 映射到内部 SKU 或履约绑定规则 |
| `buyNum` | 购买数量 | 生成对应数量的履约任务 |
| `maxAmount` | 成本上限校验 | 可选,超限返回失败 |
| `callbackUrl` | 备用回调地址 | 先保留,不作为主流程依赖 |
| `timestamp` | 防重放 | 校验请求时效 |
| `version` | 版本 | 固定 `1.0` |
| `sign` | 验签 | 必填 |
### 5.2 当前项目内部建议映射
建议新增一个独立来源:
- `provider = '91kaquan'`
- `platform = 'kuaishou'`
商品绑定建议:
- `productNo` 对应当前项目内部 `skuCode`
- 再由现有快手履约配置,匹配到 `kuaishou_ct_assisted` 履约链路
## 6. 异步下单接口配置
### 6.1 请求方向
- `91卡券 -> 当前项目`
### 6.2 请求地址
```text
POST /api/v1/open/91/orders/create
Content-Type: application/json;charset=utf-8
```
### 6.3 请求参数
| 参数名 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | 是 | string | 91 商家订单号,唯一 |
| `productNo` | 是 | string | 我方商品编号 |
| `buyNum` | 是 | int | 购买数量 |
| `maxAmount` | 否 | string | 可接受最大成本金额 |
| `callbackUrl` | 否 | string | 91 提供的回调地址 |
| `timestamp` | 是 | long | 10 位秒级时间戳 |
| `version` | 是 | string | 固定 `1.0` |
| `sign` | 是 | string | 签名 |
### 6.4 请求示例
```json
{
"orderNo": "P91KS202605040001",
"productNo": "KS-CLOUD-SKU-001",
"buyNum": 1,
"maxAmount": "0.0000",
"callbackUrl": "https://cb.example.com/notify/91/order",
"timestamp": 1777867200,
"version": "1.0",
"sign": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```
### 6.5 下单处理规则
- 验签失败:直接返回失败。
- `orderNo` 已存在:按幂等处理,返回已有订单状态。
- `productNo` 未配置:返回失败。
- 成本超限:返回失败,错误码可用 `1220`
- 下单成功后:
- 创建内部订单;
- 创建快手履约任务;
- 生成领取链接;
- 异步商品首次响应返回 `10`,表示处理中。
### 6.6 响应字段约定
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | string | 是 | 原样返回 |
| `outTradeNo` | string | 是 | 我方内部订单号 |
| `orderStatus` | int | 是 | 异步商品固定返回 `10``30` |
| `orderCost` | decimal | 否 | 成功受理时可返回 |
| `cards` | string | 否 | 异步下单阶段建议为空 |
### 6.7 响应示例
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 10,
"orderCost": 0.0000,
"cards": ""
}
}
```
## 7. 查询订单接口配置
### 7.1 请求方向
- `91卡券 -> 当前项目`
### 7.2 请求地址
```text
POST /api/v1/open/91/orders/query
Content-Type: application/json;charset=utf-8
```
### 7.3 请求参数
| 参数名 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | 是 | string | 91 商家订单号 |
| `timestamp` | 是 | long | 10 位秒级时间戳 |
| `version` | 是 | string | 固定 `1.0` |
| `sign` | 是 | string | 签名 |
### 7.4 查询处理规则
- 找不到订单:返回失败。
- 订单已创建但领取链接未准备好:返回 `orderStatus = 10`
- 领取链接已生成,可交付:返回 `orderStatus = 20`
- 订单无法履约:返回 `orderStatus = 30`,并带失败原因。
### 7.5 响应字段约定
| 参数名 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `orderNo` | string | 是 | 原样返回 |
| `outTradeNo` | string | 是 | 我方内部订单号 |
| `orderStatus` | int | 是 | `10`处理中,`20`成功,`30`失败 |
| `failCode` | int | 否 | 失败时返回 |
| `failReason` | string | 否 | 失败时返回 |
| `orderCost` | decimal | 否 | 成功时返回 |
| `cards` | string | 成功时必须 | 卡密加密串 |
## 8. cards 字段配置
### 8.1 推荐方案
既然已确认允许将链接作为最终卡密内容展示给买家,建议:
- `cardNo` 直接放领取链接;
- `cardPwd` 留空;
- `expireTime` 可放领取链接过期时间;
- `jumpLink` 可与 `cardNo` 保持一致,作为兼容字段。
这样做的好处是:
- `91卡券` 自动发货可直接展示链接;
- 复杂文案、快手操作说明、核销码校验、角色确认,全部放在我方领取页完成;
- 降低 91 展示层格式差异带来的风险。
### 8.2 单卡结构建议
```json
[
{
"cardNo": "https://你的域名/claim/abc123xyz",
"cardPwd": "",
"expireTime": "2026-05-05 12:00:00",
"jumpLink": "https://你的域名/claim/abc123xyz"
}
]
```
### 8.3 多数量建议
如果 `buyNum > 1`
- 每个数量生成一个独立领取链接;
- `cards` 中放多个卡项;
- 每个 `cardNo` 对应一个独立链接。
## 9. 查询成功响应示例
```json
{
"code": 200,
"message": "接口调用成功",
"data": {
"orderNo": "P91KS202605040001",
"outTradeNo": "OS202605040001",
"orderStatus": 20,
"failCode": 0,
"failReason": "",
"orderCost": 0.0000,
"cards": "加密后的cards字符串"
}
}
```
`cards` 解密前原始结构建议为:
```json
[
{
"cardNo": "https://你的域名/claim/abc123xyz",
"cardPwd": "",
"expireTime": "2026-05-05 12:00:00",
"jumpLink": "https://你的域名/claim/abc123xyz"
}
]
```
## 10. 状态流转建议
### 10.1 91侧状态
- `10`: 已下单,当前项目正在生成领取链接
- `20`: 已可交付,91 可自动发货给买家
- `30`: 无法履约
### 10.2 当前项目侧状态建议
- 创建订单成功:进入待履约
- 已生成 `claimUrl`:视为可交付
- 查询接口检测到 `claimUrl` 已存在:返回 `20`
- 配置缺失、商品未匹配、履约初始化失败:返回 `30`
## 11. 商品配置建议
建议在你方给 91 的商品配置中约定:
- `productNo`:对应当前项目内部的快手履约 SKU
- 商品名称:明确标注“自动发链接”
- 发货类型:异步卡密
- 买家收到内容:领取链接
## 12. 对接方需确认的固定项
发给 `91卡券` 客服/对接方时,建议一次性确认以下配置:
- 异步卡密下单 URL
- 查询订单 URL
- `userId`
- 商户密钥
- 签名算法是否按本文档固定
- `cards``cardNo` 直接展示链接是否按预期显示
- `jumpLink` 是否会同步展示或仅作兼容字段
- 查询频率与超时要求
## 13. 最终建议
这次对接的最稳方案是:
- `91` 负责卖货与自动发货;
- 当前项目负责生成 `claimUrl`
- `claimUrl` 作为最终卡密内容,通过 `cards.cardNo` 返回;
- 所有快手专属引导和后续交互,都留在当前项目领取页中完成。
这样对当前项目改动最小,也最符合现在快手 Cloud 履约链路的设计。