12 KiB
幸运礼物外接接口对接文档
文档版本:2026-07-15
接入方式:服务端对服务端(Server-to-Server)
金额单位:对接 App 的金币最小整数单位
1. 接口用途
外部 App 在自己的账务系统完成幸运礼物扣费后,调用本接口获取一次最终抽奖结果。
平台负责:
- 按
app_code隔离规则、奖池、RTP 和抽奖流水。 - 按
app_code + request_id保证抽奖幂等。 - 返回最终
reward_amount和倍率。
对接 App 负责:
- 调用前完成用户扣费。
- 从自己的账务和用户主数据提供真实的扣费时间、稳定设备标识和账号注册时间。
- 在自己的鉴权或请求签名边界内绑定上述业务事实,不能让 App 或 Web 客户端直接伪造。
- 成功收到结果后,在自己的账务系统中向用户发放
reward_amount。 - 对超时或网络失败使用原
request_id重试,不得重新生成业务请求 ID。
HyApp 不会操作外部 App 的用户钱包。reward_status=granted 表示抽奖结果已经生成并交给调用方,不表示奖励已在外部 App 入账。
2. 接口地址
| 类型 | 地址 |
|---|---|
| Base URL | https://lucky-api.global-interaction.com |
| 送礼接口 | POST https://lucky-api.global-interaction.com/api/v1/lucky-gifts/send |
| 就绪检查 | GET https://lucky-api.global-interaction.com/healthz/ready |
就绪检查:
GET https://lucky-api.global-interaction.com/healthz/ready
2026-07-15 实测就绪检查返回 HTTP 200,送礼请求可到达幸运礼物网关。
3. 调用前置条件
- 向平台申请唯一
app_code,并加入幸运礼物网关白名单。 - 确认该 App 的幸运礼物规则已启用。
- 对接 App 必须先扣费,再调用抽奖接口。
- 如果使用
dynamic_v3,对接 App 必须提供真实paid_at_ms;应尽量提供稳定device_id和真实user_registered_at_ms,以启用完整设备风控与 RTP 补偿资格判断。 - 本接口只允许对接 App 服务端调用,禁止将请求能力下发到 App 或 Web 客户端。
3.1 真实性与信任边界
当前 HTTP 入口只校验 app_code 是否在白名单,尚未启用 Authorization Token 或平台侧请求签名。白名单只能决定“这个 App 是否已开通”,不能独立证明某次请求中的用户、设备、扣费时间和注册时间是真实的。
对接 App 必须在自己的服务端边界内完成以下保障:
external_user_id来自已登录用户,不直接信任客户端自报值。- 提供
device_id时,必须与该次已鉴权的用户/设备关系绑定,并在同一设备的后续请求中保持稳定;不能用随机数、请求号或会话 token 临时代替。无法提供时应保持为空,平台会跳过设备日上限而不是伪造设备。 paid_at_ms由扣费成功的账务事实产生,user_registered_at_ms从用户主数据读取,不使用幸运礼物接口的收包时间或用户首次抽奖时间代替。- 如果对接 App 自身使用请求签名,签名内容必须覆盖这些字段;重试时必须保持原始业务事实不变。
4. 发送幸运礼物
4.1 请求
POST /api/v1/lucky-gifts/send HTTP/1.1
Host: lucky-api.global-interaction.com
Content-Type: application/json
X-Request-Id: trace-20260715-000001
X-Request-Id 为可选的链路追踪 ID。如果不传,平台会自动生成。它只用于日志排查,不是抽奖幂等键。
4.2 请求体
{
"app_code": "partner_app",
"request_id": "gift-order-20260715-000001",
"external_user_id": "user-10001",
"device_id": "device-installation-7f80d90b",
"gift_count": 3,
"unit_amount": 100,
"paid_at_ms": 1784073590000,
"user_registered_at_ms": 1783814400000,
"currency": "COIN",
"metadata": {
"external_order_id": "order-1000001",
"gift_id": "lucky-rose",
"room_id": "room-20001"
}
}
4.3 字段说明
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
app_code |
string | 是 | 去除首尾空格后 1–32 字符 | 平台分配的 App 编码;按小写存储和校验。 |
request_id |
string | 是 | 去除首尾空格后 1–128 字符 | 对接 App 生成的业务幂等 ID;建议直接使用送礼订单号或 UUID。 |
external_user_id |
string | 是 | 去除首尾空格后 1–128 字符 | 用户在对接 App 中的稳定唯一 ID。 |
device_id |
string | 否 | 空或去除首尾空格后 1–128 字符 | 提供可信稳定值时启用设备日返奖上限;缺失时只跳过设备维度,其他返奖上限继续生效。不得每次请求重新生成。 |
gift_count |
int64 | 是 | > 0 |
本次已扣费的礼物数量。 |
unit_amount |
int64 | 是 | > 0 |
单个礼物的金币整数价格。 |
paid_at_ms |
int64 | dynamic_v3 是 |
> 0,Unix epoch milliseconds |
对接 App 账务系统完成本次扣费的真实 UTC 时间;系统不会用接口收到请求的时间代替。 |
user_registered_at_ms |
int64 | dynamic_v3 业务必填 |
> 0,Unix epoch milliseconds |
用户账号的真实创建时间,必须从对接 App 的用户主数据获取。技术上缺失不会阻断普通抽奖,但系统会按不满足注册 48 小时处理,关闭该用户的 RTP 补偿大奖资格。 |
currency |
string | 否 | 只支持 COIN |
缺省或空字符串时按 COIN 处理。 |
metadata |
object | 否 | JSON object | 对接方的展示或排查元数据;不参与金额、规则或幂等判定。 |
服务端按下式计算本次金额:
total_amount = gift_count * unit_amount
请求体不得传入 total_amount 或 pool_id。total_amount 由系统根据数量和单价计算,奖池由平台已发布的规则选择。接口会拒绝所有未定义的顶层字段。
dynamic_v3 下,缺失 paid_at_ms 会使整次抽奖失败;缺失 device_id 不阻断开奖,只跳过设备日返奖上限,用户、房间、主播、单次等其他上限仍生效。缺失、不合理或尚未满 48 小时的 user_registered_at_ms 不阻断普通抽奖,但 RTP 补偿大奖资格会严格按“不符合”处理。
一个请求只返回一个聚合抽奖结果;gift_count 不会产生多个独立响应。
4.4 成功响应
HTTP Status:200 OK
{
"code": 0,
"message": "ok",
"request_id": "trace-20260715-000001",
"data": {
"draw_id": "external_lucky_draw_xxxxxxxxxx",
"request_id": "gift-order-20260715-000001",
"app_code": "partner_app",
"external_user_id": "user-10001",
"gift_count": 3,
"unit_amount": 100,
"total_amount": 300,
"reward_amount": 600,
"multiplier_ppm": 2000000,
"reward_status": "granted",
"rule_version": 1,
"created_at_ms": 1784073600000
}
}
4.5 响应字段
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 业务结果码;0 表示请求成功。 |
message |
string | 结果说明。 |
外层 request_id |
string | HTTP 链路追踪 ID,来自 X-Request-Id 或由平台生成。 |
data.draw_id |
string | 平台生成的唯一抽奖 ID,对账时使用。 |
data.request_id |
string | 请求体中的业务幂等 ID。 |
data.app_code |
string | 归一化后的 App 编码。 |
data.external_user_id |
string | 对接 App 的用户 ID。 |
data.gift_count |
int64 | 礼物数量。 |
data.unit_amount |
int64 | 单件礼物金币价格。 |
data.total_amount |
int64 | 服务端计算的已扣费总额。 |
data.reward_amount |
int64 | 对接 App 应向用户发放的金币整数金额;以该字段为最终结算依据。 |
data.multiplier_ppm |
int64 | 倍率 ppm;1000000 表示 1x,2000000 表示 2x。 |
data.reward_status |
string | 当前为 granted,表示抽奖已完成且结果已交给对接 App 处理。 |
data.rule_version |
int64 | 本次抽奖命中的规则版本。 |
data.created_at_ms |
int64 | 抽奖结果创建时间,Unix epoch milliseconds,UTC。 |
未中奖时 reward_amount 和 multiplier_ppm 为 0。当前 JSON 序列化会省略数值为 0 的结果字段,对接方必须将缺失的 reward_amount 或 multiplier_ppm 按 0 处理,不得将字段缺失视为请求失败。
5. 幂等与重试
幂等键固定为:
app_code + request_id
- 首次请求成功后,平台保存抽奖结果。
- 使用相同
app_code + request_id重试时,直接返回首次结果,不会重新抽奖。 - 同一
request_id不得对应不同用户、数量或金额。平台在幂等命中时会返回首次结果,不会用新参数覆盖。 - 超时、连接中断或 HTTP 5xx 时,使用原请求体和原
request_id重试。 - 客户端超时建议设置为大于网关内部 3 秒处理超时,并对重试使用有上限的退避。
如果多次重试后仍无法确认结果,请保留 app_code、request_id、外层 request_id 和扣费流水,由平台根据抽奖记录对账。
6. 错误响应
6.1 统一格式
{
"code": 40000,
"message": "request_id is required",
"request_id": "trace-20260715-000001"
}
6.2 错误码
| HTTP Status | code |
场景 | 对接方动作 |
|---|---|---|---|
| 400 | 40000 | JSON 无效、出现未定义字段、必填字段缺失、金额非正数或币种不支持 | 修正请求,不要原样重试。 |
| 403 | 40300 | app_code 未加入当前环境白名单 |
联系平台开通或检查环境。 |
| 404 | 无统一业务码 | 请求路径或 HTTP 方法错误 | 检查 Base URL、路径和请求方法。 |
| 500 | 50000 | 抽奖服务超时、内部处理失败,或 dynamic_v3 在规则层发现 paid_at_ms 缺失 |
先本地校验 V3 扣费事实已齐全;事实齐全时保持原 request_id 重试,不得重新扣费。 |
业务成功必须同时满足 HTTP Status 为 200 且响应 code 为 0。
7. cURL 示例
curl --request POST \
'https://lucky-api.global-interaction.com/api/v1/lucky-gifts/send' \
--header 'Content-Type: application/json' \
--header 'X-Request-Id: trace-20260715-000001' \
--data '{
"app_code": "partner_app",
"request_id": "gift-order-20260715-000001",
"external_user_id": "user-10001",
"device_id": "device-installation-7f80d90b",
"gift_count": 3,
"unit_amount": 100,
"paid_at_ms": 1784073590000,
"user_registered_at_ms": 1783814400000,
"currency": "COIN",
"metadata": {
"external_order_id": "order-1000001",
"gift_id": "lucky-rose",
"room_id": "room-20001"
}
}'
8. 标准处理流程
- 对接 App 在已鉴权的服务端上确定
external_user_id、稳定device_id和用户主数据中的user_registered_at_ms。 - 对接 App 生成全局唯一的
request_id。 - 对接 App 在自有账务系统扣除
gift_count * unit_amount,并以扣费成功事实的 UTC 毫秒时间作为paid_at_ms。 - 对接 App 调用幸运礼物接口,一次传入上述业务事实。
- 平台按
app_code + request_id创建或返回已有抽奖结果。 - 对接 App 在响应成功后按
reward_amount入账,并保存draw_id。 - 任何未知结果都使用原
request_id和原始业务事实重试;禁止重复扣费或重新生成抽奖业务号。
9. 联调检查清单
app_code已加入幸运礼物网关白名单。- 规则已启用,并确认金币单位一致。
dynamic_v3请求中的paid_at_ms来自真实扣费事实,不是当前时间的临时填充值。device_id已绑定已鉴权设备且跨请求稳定,不用请求号或会话 token 代替。user_registered_at_ms来自用户主数据;已验证缺失时普通抽奖可继续、RTP 补偿大奖资格会关闭。- 调用能力仅保留在对接 App 服务端,上述业务事实已纳入自身鉴权或请求签名边界。
- 正常送礼可获得 HTTP 200 /
code=0。 - 重复发送相同
request_id可获得相同draw_id和结果。 - 模拟超时后只重试抽奖请求,不重复扣费。
- 未中奖响应中缺失的数值字段可正确按
0处理。 - 奖励按
reward_amount在外部 App 入账,并持久化draw_id。 - 上线前完成小额真实扣费、抽奖、返奖和幂等重试验收。