接入你的 App

Xsolla 订阅

适合通过 Xsolla 卖订阅、自己没有服务端的 App。App 用一个 API 密钥把 Xsolla 用户 ID 发给网关;网关用你的 Xsolla API 密钥去问 Xsolla,回答该用户有没有生效中的订阅。验证免费。

#开始之前

  • 一个 Xsolla Publisher Account,其中有卖订阅的项目(Subscriptions → Subscription plans)。
  • App 写进支付令牌的用户 ID(user.id)。同一个用户每次都要一样,比如 App 首次生成后保存下来的 ID。

#1. 拿到 ID 和 API 密钥

  1. 1

    打开 Publisher Account

    publisher.xsolla.com

    用有权限管理 API 密钥的账号登录。

  2. 2

    记下商户 ID 和项目 ID

    打开项目,地址是 publisher.xsolla.com/<商户 ID>/projects/<项目 ID>,例如 746076 和 273204。

  3. 3

    创建 API 密钥

    Company settings → API keys → Create API key,或项目的 Settings → API keys

    马上复制:Xsolla 只显示一次。拿到它的人能读取你的订阅,所以不要放进 App。

#2. 填到 API 密钥上

  1. 1

    打开 App 用的那个密钥

    控制台 → API 密钥 → 编辑

    给 App 单独建一个密钥,只开放它用到的模型,并设置额度上限。

  2. 2

    填写 Xsolla 订阅验证

    设置 Xsolla 验证

    填写商户 ID、项目 ID 和 API 密钥后保存。网关会先用这个密钥问一次 Xsolla 再保存;密钥加密保存,之后不再显示。

#3. 在 App 里验证

付款窗口关闭后查一次,App 打开时再查一次。传 App 写进支付令牌的同一个用户 ID。不要等结果才启动 App:先显示上次保存的结果,查完再更新。每个密钥默认每分钟可查 120 次。

xsolla.dart
import 'dart:convert';
import 'package:http/http.dart' as http;

const apiKey = 'sk-YOUR_KEY';

Future<Map<String, dynamic>?> checkXsolla(String userId) async {
  final res = await http.post(
    Uri.parse('https://www.aisplice.store/v1/xsolla/verify'),
    headers: {
      'Authorization': 'Bearer $apiKey',
      'Content-Type': 'application/json',
      // Request signing on for this key? Then this call must be signed too:
      // ...signedHeaders('POST', '/v1/xsolla/verify'),
    },
    body: jsonEncode({'user_id': userId}),
  );
  if (res.statusCode != 200) return null; // keep the last saved answer
  return jsonDecode(res.body) as Map<String, dynamic>;
}

Future<void> refreshEntitlement(String userId) async {
  final status = await checkXsolla(userId);
  if (status == null) return;
  await saveEntitlement(status); // your local storage
  if (status['active'] == true) unlockPaidFeatures();
}

#4. 决定解锁什么

验证结果App 怎么做常见原因
active: true, in_trial: true解锁,并按 expiry_time 显示“试用到期时间”。免费试用,还没扣款
active: true解锁,有效到 expiry_time。已付费,包括关闭了自动续费但还没到期的订阅
subscribed: true, active: false不解锁,显示续订页面。已取消或已冻结
subscribed: false不解锁,显示订阅页面。该用户还没有订阅,或付款还没完成
HTTP 502 / 503沿用上次保存的结果,稍后重试。Xsolla 或 API 密钥没有回应

把 expiry_time 和结果一起保存。两次验证之间,到这个时间之前都当作可用,这样手机离线也能正常用。

#5. 保护 App 里的密钥

放在 App 里的 key 抓包就能看到。给这个 key 开启请求签名,这样别人复制走 key 也单独用不了;打包时做混淆,并给 key 设额度上限。

App 请求签名 →

#6. 查看发生了什么

每次验证(包括缓存结果和失败)都会列在控制台 → 请求日志里,是密钥上的一条免费 xsolla-verify 记录。

  • 保存时提示 Xsolla 不接受密钥:密钥没复制全、已被删除,或属于别的公司。请新建一个。
  • xsolla_credentials_invalid:保存后密钥在 Publisher Account 里被删了。请新建密钥并填到 API 密钥上。
  • 每次都返回 subscribed: false:用户 ID 和支付令牌里的不一致,或密钥上的项目 ID 是另一个项目。

全部字段和错误码 →

还是没解决?

把请求 ID 或报错信息发给我们,我们来查。