6.9 KiB
6.9 KiB
贩卖机硬件 API 对接文档
基本信息
- 基础地址:
https://your-domain.com/api/vending - 数据格式:JSON
- 字符编码:UTF-8
- 所有请求需在 Header 中携带
X-Machine-Id(贩卖机唯一标识)
通用响应格式
{
"success": true,
"data": {},
"message": ""
}
| 字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 请求是否成功 |
| data | object/null | 响应数据,失败时可能为 null |
| message | string | 提示信息,失败时为错误原因 |
对接流程
用户打开 APP 展示会员二维码(含 token,5 分钟有效)
│
▼
贩卖机扫描二维码,提取 token
│
▼
调用【接口1】获取用户信息
│
├── 返回 isLocked: true → 提示"该用户已在其他机器操作中"
├── 返回 isMember: false → 提示"非会员用户"(正常情况不会出现)
└── 返回正常用户信息 + 优惠券列表
│
▼
用户选择商品,贩卖机根据优惠券信息判断是否使用优惠券
(每次只能使用一张,优先使用快到期、抵扣金额最大的)
│
▼
用户完成支付(或取消/失败)
│
▼
调用【接口2】上报支付结果(无论成功或失败都必须调用)
接口1:获取用户信息
贩卖机扫描用户二维码后,通过此接口获取用户会员信息和可用优惠券列表。
调用成功后,系统会自动锁定该用户(防止同时在多台机器操作),并使二维码失效(防止截图盗刷)。
请求
POST /api/vending/user-info
Headers:
| 名称 | 必填 | 说明 |
|---|---|---|
| Content-Type | 是 | application/json |
| X-Machine-Id | 是 | 贩卖机唯一标识 |
Body:
{
"qrcodeToken": "用户二维码中包含的 token 字符串"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| qrcodeToken | string | 是 | 从用户二维码中解析出的 token |
响应
成功(正常用户):
{
"success": true,
"data": {
"userId": "user_abc123",
"isMember": true,
"isLocked": false,
"coupons": [
{
"couponId": "coupon_001",
"type": "thresholddiscount",
"thresholdAmount": 100.00,
"discountAmount": 5.00,
"expireAt": "2026-04-30T23:59:59Z"
},
{
"couponId": "coupon_002",
"type": "directdiscount",
"thresholdAmount": null,
"discountAmount": 3.00,
"expireAt": "2026-05-15T23:59:59Z"
}
]
},
"message": ""
}
成功(用户已被其他机器锁定):
{
"success": true,
"data": {
"userId": "user_abc123",
"isMember": true,
"isLocked": true,
"coupons": []
},
"message": ""
}
响应字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| userId | string | 用户唯一标识 |
| isMember | boolean | 是否为会员 |
| isLocked | boolean | 是否已被其他贩卖机锁定。为 true 时应提示用户"已在其他机器操作中" |
| coupons | array | 用户可用优惠券列表(已按规则排序) |
优惠券字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| couponId | string | 优惠券 ID,支付回调时需回传 |
| type | string | 优惠券类型:thresholddiscount(满减券)、directdiscount(抵扣券) |
| thresholdAmount | decimal/null | 满减门槛金额。满减券时有值,抵扣券时为 null |
| discountAmount | decimal | 抵扣金额 |
| expireAt | string | 到期时间(UTC,ISO 8601 格式) |
优惠券排序规则(已由服务端排好序):
- 到期时间升序(快到期的排前面)
- 到期时间相同时,抵扣金额降序(金额大的排前面)
优惠券使用规则:
- 每次交易只能使用一张优惠券
- 满减券:用户消费金额 ≥ thresholdAmount 时可使用
- 抵扣券:无门槛,直接抵扣
- 建议优先使用列表中排在前面的优惠券(已按最优顺序排列)
错误响应
| 场景 | success | message |
|---|---|---|
| 二维码无效或已过期 | false | 二维码无效或已过期 |
| 用户不存在 | false | 用户不存在 |
接口2:支付结果回调
用户在贩卖机完成支付后(无论成功、失败或取消),贩卖机必须调用此接口上报支付结果。
系统会根据支付结果:
- 支付成功:发放积分、核销优惠券、解除用户锁定
- 支付失败/取消:仅解除用户锁定
重要:无论支付结果如何,都必须调用此接口,否则用户将保持锁定状态(10 分钟后自动超时解锁)。
请求
POST /api/vending/payment-callback
Headers:
| 名称 | 必填 | 说明 |
|---|---|---|
| Content-Type | 是 | application/json |
| X-Machine-Id | 是 | 贩卖机唯一标识 |
Body:
{
"userId": "user_abc123",
"machineId": "machine_001",
"paymentAmount": 50.00,
"usedCouponId": "coupon_001",
"paymentStatus": "success",
"transactionId": "txn_20260408_001"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| userId | string | 是 | 用户 ID(从接口1获取) |
| machineId | string | 是 | 贩卖机 ID |
| paymentAmount | decimal | 是 | 用户实际支付金额(优惠券抵扣后的金额) |
| usedCouponId | string | 否 | 使用的优惠券 ID,未使用时传 null 或不传 |
| paymentStatus | string | 是 | 支付状态:success(成功)、failed(失败)、cancelled(取消) |
| transactionId | string | 是 | 贩卖机端的交易流水号(用于对账) |
响应
成功:
{
"success": true,
"data": null,
"message": "支付回调处理成功"
}
错误响应
| 场景 | success | message |
|---|---|---|
| 用户不存在 | false | 用户不存在 |
| 处理异常 | false | 支付回调处理失败 |
附录
用户锁定机制
- 调用接口1成功获取用户信息后,系统自动锁定该用户
- 锁定期间,其他贩卖机扫同一用户的二维码,接口1会返回
isLocked: true - 调用接口2后,系统自动解除锁定
- 安全兜底:锁定 10 分钟后自动超时解锁(防止贩卖机异常未调用接口2)
二维码说明
- 二维码由用户 APP 端生成,有效期 5 分钟
- 二维码内容为一个 token 字符串,贩卖机扫码后提取该 token 调用接口1
- 每个二维码只能使用一次,扫码成功后立即失效
- 用户可重新生成新的二维码
积分发放规则
- 仅会员用户支付成功时发放积分
- 积分 = 支付金额 × 转换比(后台可配置,默认 1 元 = 1 积分)
- 积分发放由系统在接口2处理时自动完成,无需贩卖机额外操作