1053 lines
25 KiB
Markdown
1053 lines
25 KiB
Markdown
# 新版 VIP 权限策略 Flutter 客户端对接文档
|
||
|
||
## 1. VIP 权限策略
|
||
|
||
### 1.1 权限来源
|
||
|
||
- VIP 等级只用于套餐名称、价格、有效期和等级展示。
|
||
- Flutter 只使用 `GET /api/v1/vip/me` 返回的 `data.state.effective_benefits` 判断当前用户是否具有某项权益。
|
||
- Flutter 不得使用 `VIP等级 >= N`、`unlock_level`、`app_code` 或本地权益表推导权限。
|
||
- `/api/v1/vip/packages` 中的 `packages[].benefits` 是该套餐当前配置的完整权益集合,只用于套餐页和升级引导,不能作为用户已拥有权益。
|
||
- 写操作最终以对应业务接口的服务端鉴权结果为准。Flutter 的权益判断只用于入口显隐、锁态和交互预判。
|
||
|
||
### 1.2 Flutter 权益状态
|
||
|
||
```dart
|
||
class VipEntitlementState {
|
||
final VipProgramConfig program;
|
||
final VipIdentity effectiveVip;
|
||
final String effectiveSource; // paid / trial / none
|
||
final Map<String, VipBenefit> benefitsByCode;
|
||
final VipUserSettings settings;
|
||
final int evaluatedAtMs;
|
||
|
||
bool has(String benefitCode) {
|
||
return program.status == 'active' &&
|
||
effectiveVip.active &&
|
||
benefitsByCode[benefitCode]?.status == 'active';
|
||
}
|
||
|
||
bool allowsRoomEntryNotice() {
|
||
return has('room_entry_notice') && settings.roomEntryNoticeEnabled;
|
||
}
|
||
|
||
bool allowsOnlineGlobalNotice() {
|
||
return has('online_global_notice') &&
|
||
settings.onlineGlobalNoticeEnabled;
|
||
}
|
||
}
|
||
```
|
||
|
||
`benefitsByCode` 必须由 `state.effective_benefits` 转换。未知 `benefit_code` 保留在状态中但不自动开放功能,不得导致解析失败或页面崩溃。
|
||
|
||
### 1.3 权益刷新
|
||
|
||
| 场景 | Flutter 处理 |
|
||
|---|---|
|
||
| 登录成功、切换账号、切换 App | 清空原 VIP 状态,调用 `/vip/me` |
|
||
| App 冷启动、回到前台 | 调用 `/vip/me` 校准过期、体验卡回落和后台配置变更 |
|
||
| 进入 VIP 页面 | 并发调用 `/vip/packages` 和 `/vip/me` |
|
||
| 购买、佩戴体验卡、卸下体验卡成功 | 使用响应中的 `state` 原子替换本地状态 |
|
||
| 收到 `vip_notice` | 按 `event_id` 去重,再调用 `/vip/me` |
|
||
| `config_version` 不一致 | 用户权限以 `/vip/me.state` 为准,重新请求 `/vip/packages`,不得合并不同版本的权益数组 |
|
||
| VIP 到期倒计时结束 | 可更新页面显示,但执行功能前仍以服务端接口结果为准 |
|
||
|
||
### 1.4 Fami 初始等级权益
|
||
|
||
下表只用于识别初始配置。Flutter 实际必须渲染 `/vip/packages` 返回的数据。
|
||
|
||
| 等级 | 本级初始新增权益 |
|
||
|---|---|
|
||
| VIP1 | `vip_badge_identity`、`vip_medal`、`avatar_frame`、`vip_title` |
|
||
| VIP2 | `chat_bubble`、`vip_gift`、`entry_effect`、`visitor_history` |
|
||
| VIP3 | `voice_wave`、`profile_card`、`custom_room_background`、`room_image_message` |
|
||
| VIP4 | `animated_avatar`、`animated_room_cover`、`mic_skin`、`room_border`、`vehicle` |
|
||
| VIP5 | `colored_room_name`、`colored_nickname`、`colored_id`、`gift_tray_skin` |
|
||
| VIP6 | `hide_profile_data`、`custom_avatar_frame`、`leaderboard_invisible`、`daily_coin_rebate` |
|
||
| VIP7 | `custom_profile_card`、`anonymous_profile_visit`、`custom_gift` |
|
||
| VIP8 | `room_entry_notice`、`custom_pretty_id`、`custom_vehicle` |
|
||
| VIP9 | `anti_kick`、`anti_mute`、`online_global_notice` |
|
||
|
||
## 2. 通用协议
|
||
|
||
- API 前缀:`/api/v1`。
|
||
- 请求头:`Authorization: Bearer <access_token>`。
|
||
- `app_code`、`user_id` 从登录态解析,Flutter 不传。
|
||
- 时间字段统一使用 Unix epoch milliseconds。
|
||
- 业务切日使用 UTC,Flutter 仅在展示时转换本地时间。
|
||
- 成功响应统一格式:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_xxx",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
- `request_id` 只用于链路追踪。
|
||
- 带 `command_id` 的接口,网络重试必须复用原 `command_id`;新的业务动作必须生成新值。
|
||
|
||
## 3. VIP 套餐
|
||
|
||
### 接口地址
|
||
|
||
`GET /api/v1/vip/packages`
|
||
|
||
### 参数
|
||
|
||
无。
|
||
|
||
### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_packages",
|
||
"data": {
|
||
"current_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true,
|
||
"started_at_ms": 1780000000000,
|
||
"expires_at_ms": 1782592000000,
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7
|
||
},
|
||
"packages": [
|
||
{
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"status": "active",
|
||
"price_coin": 4000,
|
||
"duration_ms": 2592000000,
|
||
"reward_resource_group_id": 0,
|
||
"reward_items": [],
|
||
"can_purchase": true,
|
||
"sort_order": 40,
|
||
"recharge_gate_required": false,
|
||
"required_recharge_coin_amount": 0,
|
||
"user_recharge_coin_amount": 0,
|
||
"purchase_locked_reason": "",
|
||
"benefits": [
|
||
{
|
||
"benefit_code": "custom_room_background",
|
||
"name": "自定义房间背景",
|
||
"benefit_type": "function",
|
||
"unlock_level": 3,
|
||
"status": "active",
|
||
"trial_enabled": true,
|
||
"resource_id": 0,
|
||
"resource_type": "",
|
||
"execution_scope": "room",
|
||
"auto_equip": false,
|
||
"sort_order": 110,
|
||
"metadata_json": ""
|
||
}
|
||
],
|
||
"config_version": 7
|
||
}
|
||
],
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1",
|
||
"level_count": 9,
|
||
"same_level_expiry_policy": "extend_remaining",
|
||
"upgrade_expiry_policy": "replace_from_now",
|
||
"downgrade_purchase_policy": "reject",
|
||
"benefit_inheritance_policy": "target_only",
|
||
"grant_mode": "trial_card",
|
||
"trial_card_enabled": true,
|
||
"status": "active",
|
||
"config_version": 7
|
||
},
|
||
"state": {
|
||
"paid_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true,
|
||
"expires_at_ms": 1782592000000
|
||
},
|
||
"equipped_trial_card": null,
|
||
"effective_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true,
|
||
"expires_at_ms": 1782592000000
|
||
},
|
||
"effective_source": "paid",
|
||
"effective_benefits": [
|
||
{
|
||
"benefit_code": "custom_room_background",
|
||
"status": "active"
|
||
}
|
||
],
|
||
"evaluated_at_ms": 1780000000000,
|
||
"user_settings": {
|
||
"room_entry_notice_enabled": true,
|
||
"online_global_notice_enabled": true,
|
||
"updated_at_ms": 0
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 4. 当前 VIP 权限状态
|
||
|
||
### 接口地址
|
||
|
||
`GET /api/v1/vip/me`
|
||
|
||
### 参数
|
||
|
||
无。
|
||
|
||
### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_vip_me",
|
||
"data": {
|
||
"level": 8,
|
||
"name": "VIP8",
|
||
"active": true,
|
||
"started_at_ms": 1780100000000,
|
||
"expires_at_ms": 1782692000000,
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7,
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1",
|
||
"level_count": 9,
|
||
"same_level_expiry_policy": "extend_remaining",
|
||
"upgrade_expiry_policy": "replace_from_now",
|
||
"downgrade_purchase_policy": "reject",
|
||
"benefit_inheritance_policy": "target_only",
|
||
"grant_mode": "trial_card",
|
||
"trial_card_enabled": true,
|
||
"status": "active",
|
||
"config_version": 7
|
||
},
|
||
"state": {
|
||
"paid_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true,
|
||
"started_at_ms": 1780000000000,
|
||
"expires_at_ms": 1782592000000,
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7
|
||
},
|
||
"equipped_trial_card": {
|
||
"trial_card_id": "vip_trial_card_xxx",
|
||
"entitlement_id": "ent_xxx",
|
||
"resource_id": 108,
|
||
"user_id": 10001,
|
||
"level": 8,
|
||
"name": "VIP8",
|
||
"status": "active",
|
||
"equipped": true,
|
||
"duration_ms": 2592000000,
|
||
"effective_at_ms": 1780100000000,
|
||
"expires_at_ms": 1782692000000,
|
||
"remaining_duration_ms": 2591000000
|
||
},
|
||
"effective_vip": {
|
||
"level": 8,
|
||
"name": "VIP8",
|
||
"active": true,
|
||
"started_at_ms": 1780100000000,
|
||
"expires_at_ms": 1782692000000,
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7
|
||
},
|
||
"effective_source": "trial",
|
||
"effective_benefits": [
|
||
{
|
||
"benefit_code": "room_entry_notice",
|
||
"name": "进房高亮通知",
|
||
"benefit_type": "function",
|
||
"status": "active",
|
||
"trial_enabled": true,
|
||
"resource_id": 0,
|
||
"resource_type": "",
|
||
"execution_scope": "room",
|
||
"auto_equip": false,
|
||
"sort_order": 290,
|
||
"metadata_json": ""
|
||
}
|
||
],
|
||
"evaluated_at_ms": 1780101000000,
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7
|
||
},
|
||
"user_settings": {
|
||
"app_code": "fami",
|
||
"user_id": 10001,
|
||
"room_entry_notice_enabled": true,
|
||
"online_global_notice_enabled": true,
|
||
"updated_at_ms": 0
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
- `effective_source`:`paid`、`trial`、`none`。
|
||
- 当前展示身份只读 `state.effective_vip`。
|
||
- 当前权限只读 `state.effective_benefits`。
|
||
- `daily_coin_rebate` 不会因体验卡进入 `effective_benefits`。
|
||
|
||
## 5. 购买、续期、升级
|
||
|
||
### 接口地址
|
||
|
||
`POST /api/v1/vip/purchase`
|
||
|
||
### 参数
|
||
|
||
```json
|
||
{
|
||
"command_id": "vip_purchase_10001_4_1780100000000",
|
||
"level": 4
|
||
}
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| `command_id` | 是 | 最长 128 字节,同一次购买重试必须复用 |
|
||
| `level` | 是 | 必须来自 `/vip/packages` |
|
||
|
||
### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_purchase",
|
||
"data": {
|
||
"order_id": "vip_order_xxx",
|
||
"transaction_id": "tx_xxx",
|
||
"vip": {
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"active": true,
|
||
"started_at_ms": 1780100000000,
|
||
"expires_at_ms": 1782692000000,
|
||
"program_type": "tiered_privilege_v1",
|
||
"config_version": 7
|
||
},
|
||
"coin_spent": 4000,
|
||
"coin_balance_after": 6000,
|
||
"reward_items": [],
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1",
|
||
"upgrade_expiry_policy": "replace_from_now",
|
||
"config_version": 7
|
||
},
|
||
"state": {
|
||
"effective_source": "paid",
|
||
"paid_vip": {
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"active": true,
|
||
"expires_at_ms": 1782692000000
|
||
},
|
||
"equipped_trial_card": null,
|
||
"effective_vip": {
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"active": true,
|
||
"expires_at_ms": 1782692000000
|
||
},
|
||
"effective_benefits": [
|
||
{
|
||
"benefit_code": "custom_room_background",
|
||
"status": "active"
|
||
}
|
||
],
|
||
"evaluated_at_ms": 1780100000000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
- 同级购买:从原截止时间继续累加。
|
||
- Fami 高等级购买:立即替换低等级,从购买时间重新计时,低等级剩余时间丢弃。
|
||
- 低等级购买:服务端拒绝。
|
||
- 购买时佩戴体验卡:付费 VIP 会更新,但 `effective_vip` 仍可能来自体验卡,必须使用响应 `state`。
|
||
|
||
## 6. VIP 体验卡
|
||
|
||
### 6.1 体验卡列表
|
||
|
||
#### 接口地址
|
||
|
||
`GET /api/v1/users/me/resources?resource_type=vip_trial_card`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 值 |
|
||
|---|---|---|---|
|
||
| `resource_type` | query | 是 | `vip_trial_card` |
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_trial_cards",
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"entitlement_id": "ent_card_a",
|
||
"resource_id": 101,
|
||
"resource": {
|
||
"resource_id": 101,
|
||
"resource_code": "vip_trial_card_3",
|
||
"resource_type": "vip_trial_card",
|
||
"name": "VIP3体验卡",
|
||
"status": "active",
|
||
"asset_url": "",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"vip_level\":3}",
|
||
"sort_order": 30
|
||
},
|
||
"status": "active",
|
||
"quantity": 1,
|
||
"remaining_quantity": 1,
|
||
"effective_at_ms": 1780100000000,
|
||
"expires_at_ms": 1781309600000,
|
||
"source_grant_id": "grant_a",
|
||
"created_at_ms": 1780100000000,
|
||
"updated_at_ms": 1780100000000,
|
||
"equipped": false
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.2 佩戴体验卡
|
||
|
||
#### 接口地址
|
||
|
||
`POST /api/v1/vip/trial-cards/{entitlement_id}/equip`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `entitlement_id` | path | 是 | 使用体验卡列表中的实例 ID |
|
||
|
||
无 body。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_trial_equip",
|
||
"data": {
|
||
"trial_card": {
|
||
"trial_card_id": "vip_trial_card_b",
|
||
"entitlement_id": "ent_card_b",
|
||
"resource_id": 102,
|
||
"user_id": 10001,
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"status": "active",
|
||
"equipped": true,
|
||
"duration_ms": 1728000000,
|
||
"effective_at_ms": 1780200000000,
|
||
"expires_at_ms": 1781928000000,
|
||
"remaining_duration_ms": 1700000000
|
||
},
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1",
|
||
"trial_card_enabled": true
|
||
},
|
||
"state": {
|
||
"effective_source": "trial",
|
||
"effective_vip": {
|
||
"level": 4,
|
||
"name": "VIP4",
|
||
"active": true,
|
||
"expires_at_ms": 1781928000000
|
||
},
|
||
"effective_benefits": []
|
||
},
|
||
"server_time_ms": 1780228000000
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.3 卸下体验卡
|
||
|
||
#### 接口地址
|
||
|
||
`DELETE /api/v1/vip/trial-cards/equipped`
|
||
|
||
#### 参数
|
||
|
||
无。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_trial_unequip",
|
||
"data": {
|
||
"unequipped": true,
|
||
"program_config": {
|
||
"app_code": "fami",
|
||
"program_type": "tiered_privilege_v1"
|
||
},
|
||
"state": {
|
||
"effective_source": "paid",
|
||
"paid_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true
|
||
},
|
||
"equipped_trial_card": null,
|
||
"effective_vip": {
|
||
"level": 3,
|
||
"name": "VIP3",
|
||
"active": true
|
||
},
|
||
"effective_benefits": []
|
||
},
|
||
"server_time_ms": 1780229000000
|
||
}
|
||
}
|
||
```
|
||
|
||
- 体验卡可自由切换,不比较等级高低。
|
||
- 切换和卸下不会暂停、延长或删除体验卡。
|
||
- 每张卡的剩余时间按绝对 `expires_at_ms` 计算。
|
||
- 佩戴和卸下成功后立即使用响应 `state` 替换本地 VIP 状态。
|
||
|
||
## 7. VIP 通知开关
|
||
|
||
### 7.1 查询开关
|
||
|
||
#### 接口地址
|
||
|
||
`GET /api/v1/vip/settings`
|
||
|
||
#### 参数
|
||
|
||
无。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_settings_get",
|
||
"data": {
|
||
"settings": {
|
||
"app_code": "fami",
|
||
"user_id": 10001,
|
||
"room_entry_notice_enabled": true,
|
||
"online_global_notice_enabled": false,
|
||
"updated_at_ms": 1780300000000
|
||
},
|
||
"evaluated_at_ms": 1780300001000
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7.2 修改开关
|
||
|
||
#### 接口地址
|
||
|
||
`PATCH /api/v1/vip/settings`
|
||
|
||
#### 参数
|
||
|
||
局部更新,至少传一个字段:
|
||
|
||
```json
|
||
{
|
||
"room_entry_notice_enabled": false,
|
||
"online_global_notice_enabled": true
|
||
}
|
||
```
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_settings_patch",
|
||
"data": {
|
||
"settings": {
|
||
"app_code": "fami",
|
||
"user_id": 10001,
|
||
"room_entry_notice_enabled": false,
|
||
"online_global_notice_enabled": true,
|
||
"updated_at_ms": 1780300010000
|
||
},
|
||
"server_time_ms": 1780300010000
|
||
}
|
||
}
|
||
```
|
||
|
||
## 8. 每日 VIP 金币返现
|
||
|
||
### 8.1 查询当前返现
|
||
|
||
#### 接口地址
|
||
|
||
`GET /api/v1/vip/coin-rebates/current`
|
||
|
||
#### 参数
|
||
|
||
无。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_rebate_current",
|
||
"data": {
|
||
"found": true,
|
||
"rebate": {
|
||
"rebate_id": "vip_rebate_xxx",
|
||
"user_id": "10001",
|
||
"task_day": "2026-07-15",
|
||
"vip_level": 6,
|
||
"vip_name": "VIP6",
|
||
"coin_amount": 100,
|
||
"status": "claimable",
|
||
"available_at_ms": 1784073600000,
|
||
"expires_at_ms": 1784160000000,
|
||
"config_version": 8,
|
||
"claimed_at_ms": 0,
|
||
"wallet_transaction_id": "",
|
||
"created_at_ms": 1784073605000,
|
||
"updated_at_ms": 1784073605000
|
||
},
|
||
"server_time_ms": 1784073610000
|
||
}
|
||
}
|
||
```
|
||
|
||
无资格时 `found=false`、`rebate=null`。
|
||
|
||
### 8.2 批量查询返现状态
|
||
|
||
#### 接口地址
|
||
|
||
`POST /api/v1/vip/coin-rebates/statuses`
|
||
|
||
#### 参数
|
||
|
||
```json
|
||
{
|
||
"rebate_ids": ["vip_rebate_xxx", "vip_rebate_yyy"],
|
||
"page": 1,
|
||
"page_size": 20
|
||
}
|
||
```
|
||
|
||
- `rebate_ids` 最多 100 个。
|
||
- 不传 `rebate_ids` 时按 `page/page_size` 查询历史。
|
||
- `page_size` 最大 100。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_rebate_statuses",
|
||
"data": {
|
||
"rebates": [
|
||
{
|
||
"rebate_id": "vip_rebate_xxx",
|
||
"task_day": "2026-07-15",
|
||
"vip_level": 6,
|
||
"vip_name": "VIP6",
|
||
"coin_amount": 100,
|
||
"status": "claimable",
|
||
"available_at_ms": 1784073600000,
|
||
"expires_at_ms": 1784160000000,
|
||
"claimed_at_ms": 0,
|
||
"wallet_transaction_id": ""
|
||
}
|
||
],
|
||
"total": 1,
|
||
"server_time_ms": 1784073610000
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.3 领取返现
|
||
|
||
#### 接口地址
|
||
|
||
`POST /api/v1/vip/coin-rebates/{rebate_id}/claim`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `rebate_id` | path | 是 | 从 current、statuses 或系统消息取得 |
|
||
|
||
```json
|
||
{
|
||
"command_id": "vip_rebate_claim_10001_20260715"
|
||
}
|
||
```
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_rebate_claim",
|
||
"data": {
|
||
"rebate": {
|
||
"rebate_id": "vip_rebate_xxx",
|
||
"task_day": "2026-07-15",
|
||
"vip_level": 6,
|
||
"vip_name": "VIP6",
|
||
"coin_amount": 100,
|
||
"status": "claimed",
|
||
"claimed_at_ms": 1784073700000,
|
||
"wallet_transaction_id": "wallet_tx_xxx"
|
||
},
|
||
"transaction_id": "wallet_tx_xxx",
|
||
"coin_balance": {
|
||
"asset_type": "COIN",
|
||
"available_amount": 20100,
|
||
"frozen_amount": 0,
|
||
"version": 18
|
||
},
|
||
"server_time_ms": 1784073700000
|
||
}
|
||
}
|
||
```
|
||
|
||
## 9. 上线全服通知
|
||
|
||
### 接口地址
|
||
|
||
`POST /api/v1/vip/online-notice`
|
||
|
||
### 参数
|
||
|
||
```json
|
||
{
|
||
"command_id": "vip_online_<process_boot_id>_2026-07-15"
|
||
}
|
||
```
|
||
|
||
- `command_id` 最长 128 字节。
|
||
- 同一进程同一 UTC 日复用同一个 `command_id`。
|
||
- `process_boot_id` 只保存在内存中,不写磁盘。
|
||
|
||
### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_online_notice",
|
||
"data": {
|
||
"event_id": "vip_online_notice:10001:sha256_digest",
|
||
"group_id": "hy_fami_bc_g_v2",
|
||
"status": "pending",
|
||
"created": true,
|
||
"evaluated_at_ms": 1784073610000
|
||
}
|
||
}
|
||
```
|
||
|
||
- `status=pending` 表示事件已进入异步投递链路。
|
||
- 幂等命中时 `created=false`,不是失败。
|
||
- 同一进程每天触发一次;杀掉进程后新进程当天可以再次触发。
|
||
|
||
## 10. 进房 VIP 通知
|
||
|
||
### 接口地址
|
||
|
||
`POST /api/v1/rooms/join`
|
||
|
||
### 参数
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_1001",
|
||
"command_id": "join_10001_room_1001_1784073600000",
|
||
"role": "audience",
|
||
"password": "",
|
||
"response_mode": "full"
|
||
}
|
||
```
|
||
|
||
### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_join",
|
||
"data": {
|
||
"result": {
|
||
"applied": true,
|
||
"room_version": 18,
|
||
"server_time_ms": 1784073600000
|
||
},
|
||
"room": {},
|
||
"viewer": {},
|
||
"seats": [],
|
||
"profiles": [],
|
||
"im": {
|
||
"group_id": "room_1001",
|
||
"need_join_group": true
|
||
},
|
||
"effective_vip": {
|
||
"program_type": "tiered_privilege_v1",
|
||
"level": 8,
|
||
"name": "VIP8",
|
||
"room_entry_notice_enabled": true
|
||
},
|
||
"server_time_ms": 1784073600000
|
||
}
|
||
}
|
||
```
|
||
|
||
本人进房首屏使用 HTTP 返回的 `data.effective_vip`。其他用户的进房效果使用当前房间 IM 消息。
|
||
|
||
## 11. VIP 装扮资源
|
||
|
||
### 11.1 我的资源列表
|
||
|
||
#### 接口地址
|
||
|
||
`GET /api/v1/users/me/resources?resource_type={resource_type}`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `resource_type` | query | 否 | `avatar_frame`、`profile_card`、`vehicle`、`chat_bubble` 等资源类型 |
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_resources",
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"entitlement_id": "ent_xxx",
|
||
"resource_id": 108,
|
||
"resource": {
|
||
"resource_id": 108,
|
||
"resource_code": "frame_vip9",
|
||
"resource_type": "avatar_frame",
|
||
"name": "VIP头像框",
|
||
"status": "active",
|
||
"asset_url": "https://cdn.example/frame.png",
|
||
"preview_url": "https://cdn.example/frame-preview.png",
|
||
"animation_url": "https://cdn.example/frame.svga",
|
||
"metadata_json": "{}",
|
||
"sort_order": 10
|
||
},
|
||
"status": "active",
|
||
"expires_at_ms": 1786665600000,
|
||
"equipped": true
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### 11.2 佩戴资源
|
||
|
||
#### 接口地址
|
||
|
||
`POST /api/v1/users/me/resources/{resource_id}/equip`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `resource_id` | path | 是 | 资源 ID |
|
||
|
||
无 body。
|
||
|
||
### 11.3 卸下资源
|
||
|
||
#### 接口地址
|
||
|
||
`DELETE /api/v1/users/me/resources/{resource_type}/unequip`
|
||
|
||
#### 参数
|
||
|
||
| 参数 | 位置 | 必填 | 说明 |
|
||
|---|---|---|---|
|
||
| `resource_type` | path | 是 | 资源类型 |
|
||
|
||
无 body。
|
||
|
||
### 11.4 当前装扮
|
||
|
||
#### 接口地址
|
||
|
||
- `GET /api/v1/appearance`
|
||
- `GET /api/v1/users/by-id/{user_id}/appearance`
|
||
|
||
#### 参数
|
||
|
||
第二个接口使用 path 参数 `user_id`。
|
||
|
||
#### 返回值
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_appearance",
|
||
"data": {
|
||
"user_id": "10001",
|
||
"avatar_frame": {},
|
||
"profile_card": {},
|
||
"vehicle": {},
|
||
"mic_seat_animation": {},
|
||
"equipped_badges": [],
|
||
"badges": [],
|
||
"resources": [],
|
||
"server_time_ms": 1784073600000
|
||
}
|
||
}
|
||
```
|
||
|
||
## 12. 相关 IM
|
||
|
||
### 12.1 VIP 激活通知
|
||
|
||
通道:腾讯云 IM C2C `TIMCustomElem`。
|
||
|
||
```json
|
||
{
|
||
"Ext": "vip_notice",
|
||
"Desc": "VipActivated",
|
||
"Data": "{\"event_type\":\"VipActivated\",\"event_id\":\"evt_xxx\",\"app_code\":\"fami\",\"transaction_id\":\"tx_xxx\",\"command_id\":\"vip_purchase_10001_4_1780100000000\",\"user_id\":\"10001\",\"source\":\"vip_purchase\",\"action\":\"upgrade\",\"previous_level\":3,\"previous_expires_at_ms\":1781396000000,\"level\":4,\"vip_name\":\"VIP4\",\"started_at_ms\":1780100000000,\"expires_at_ms\":1782692000000,\"program_type\":\"tiered_privilege_v1\",\"config_version\":7,\"expiry_policy\":\"replace_from_now\",\"created_at_ms\":1780100000000}"
|
||
}
|
||
```
|
||
|
||
Flutter 按 `event_id` 去重,然后调用 `GET /api/v1/vip/me`,不能直接使用 IM 内容生成权限。
|
||
|
||
### 12.2 进房通知
|
||
|
||
通道:当前房间腾讯云 IM 群 `TIMCustomElem`,不发送到全服群。
|
||
|
||
```json
|
||
{
|
||
"Ext": "room_system_message",
|
||
"Desc": "room_user_joined",
|
||
"Data": "{\"event_id\":\"evt_join_xxx\",\"room_id\":\"room_1001\",\"event_type\":\"room_user_joined\",\"actor_user_id\":10001,\"target_user_id\":10001,\"room_version\":18,\"role\":\"audience\",\"nickname\":\"Nina\",\"avatar\":\"https://cdn.example/avatar.png\",\"display_user_id\":\"100042\",\"pretty_display_user_id\":\"888042\",\"vip_program_type\":\"tiered_privilege_v1\",\"effective_vip_level\":\"8\",\"effective_vip_name\":\"VIP8\",\"room_entry_notice_enabled\":\"true\"}"
|
||
}
|
||
```
|
||
|
||
仅当 `event_type=room_user_joined` 且 `room_entry_notice_enabled=true` 时展示 VIP 进房效果。使用 `event_id` 去重。
|
||
|
||
### 12.3 上线全服通知
|
||
|
||
通道:全局播报群 `TIMCustomElem`。
|
||
|
||
| 字段 | 值 |
|
||
|---|---|
|
||
| `Ext` | `im_broadcast` |
|
||
| `Desc` | `vip_online_notice` |
|
||
| `Data` | 下方 JSON 字符串 |
|
||
| `CloudCustomData` | 与 `Data` 相同 |
|
||
|
||
```json
|
||
{
|
||
"event_id": "vip_online_notice:10001:sha256_digest",
|
||
"broadcast_type": "vip_online_notice",
|
||
"scope": "global",
|
||
"app_code": "fami",
|
||
"user_id": 10001,
|
||
"sender_user_id": 10001,
|
||
"nickname": "Nina",
|
||
"avatar": "https://cdn.example/avatar.png",
|
||
"avatar_frame_url": "https://cdn.example/frame.png",
|
||
"avatar_frame_resource_id": 108,
|
||
"avatar_frame_code": "frame_vip9",
|
||
"avatar_frame_asset_url": "https://cdn.example/frame.png",
|
||
"avatar_frame_preview_url": "https://cdn.example/frame-preview.png",
|
||
"avatar_frame_animation_url": "https://cdn.example/frame-animation.svga",
|
||
"display_user_id": "888042",
|
||
"raw_display_user_id": "100042",
|
||
"pretty_display_user_id": "888042",
|
||
"vip_program_type": "tiered_privilege_v1",
|
||
"vip_level": 9,
|
||
"vip_name": "VIP9",
|
||
"message": "欢迎进入Fami,祝你有美好的一天",
|
||
"action": {
|
||
"type": "none"
|
||
},
|
||
"sent_at_ms": 1784073610500
|
||
}
|
||
```
|
||
|
||
Flutter 使用 `event_id` 去重,直接使用事件内的用户、VIP 和头像框快照渲染。
|
||
|
||
### 12.4 金币返现系统消息
|
||
|
||
接口:`GET /api/v1/messages?section=system&page_size=20&page_token=`。
|
||
|
||
```json
|
||
{
|
||
"message_id": "msg_vip_rebate_xxx",
|
||
"title": "VIP金币返现",
|
||
"summary": "尊敬的VIP用户,平台今日返现100金币,请及时领取。",
|
||
"body": "尊敬的VIP用户,平台今日返现100金币,请及时领取。",
|
||
"icon_url": "",
|
||
"image_url": "",
|
||
"action_type": "vip_coin_rebate_claim",
|
||
"action_param": "{\"coin_amount\":100,\"expires_at_ms\":1784160000000,\"rebate_id\":\"vip_rebate_xxx\",\"task_day\":\"2026-07-15\"}",
|
||
"read": false,
|
||
"sent_at_ms": 1784073600000
|
||
}
|
||
```
|
||
|
||
Flutter 将 `action_param` 解析为 JSON,打开页面后调用 `/vip/coin-rebates/statuses` 获取真实领取状态。
|
||
|
||
### 12.5 IM 登录与全局群
|
||
|
||
接口:`GET /api/v1/im/usersig`。
|
||
|
||
Flutter 使用返回的 UserSig 登录腾讯云 IM,并加入响应 `join_groups` 中 `type=global_broadcast` 的群组后,再消费 `vip_online_notice`。
|