跳到正文
Indiana
控制台
章节目录 / 快速开始

快速开始

NEXT.JS APP ROUTER · TYPESCRIPT · SANDBOX

用三个 HTTP 请求完成 Customer、会话和权益读取。

下载 HTTP 接入示例
API v1更新于

开始前准备

先用 HTTP 完成 Customer → 会话 → 权益读取,无需安装 Indiana SDK。连接成功后再接入购买、余额或界面。

  • 在控制台选择 App / Sandbox,打开 SDK 接入,记录 API 地址和 App ID。
  • 创建具备 customers:write、sessions:create、entitlements:read 的 Server Key。准备 Node.js 22+ 和一个由自己登录系统验证的测试用户 ID。
  • 首次连接不需要付费 Product、Offering、Paywall 或 Funnel。

相关:Key、范围与权限

1. 配置 Sandbox

把配置写入不提交的 .env.local,再加入 INDIANA_VERIFIED_USER_ID,使用你已验证的测试用户 ID。浏览器配置在后续 Web 接入中使用。

.env.localShell
# 复制你的 App → Sandbox → SDK 接入中的配置INDIANA_BASE_URL=https://your-indiana-host.exampleINDIANA_PROJECT_ID=your-project-idINDIANA_SECRET_KEY=your-sandbox-server-key # 浏览器可见;不包含 Secret KeyNEXT_PUBLIC_INDIANA_BASE_URL=https://your-indiana-host.exampleNEXT_PUBLIC_INDIANA_PROJECT_ID=your-project-id

2. 建立身份并读取权益

保存完整脚本为 quickstart.mjs 后运行。三次请求属于同一 App / Sandbox;最后一次使用 Customer Token 读取自身数据,不传 customerId。

预期结果

输出 customerId 与 balances。同一作用域重复识别同一个 externalUserId 返回同一个 Customer。balances 为空仍表示接入成功,尚无符合条件的持有。

quickstart.mjsJavaScript
// Node.js 22+,仅在可信后端执行,不输出 Key 或 Customer Token。const required = (name) => {  const value = process.env[name];  if (!value) throw new Error(`Missing ${name}`);  return value;};const baseUrl = required("INDIANA_BASE_URL");const projectId = required("INDIANA_PROJECT_ID");const serverKey = required("INDIANA_SECRET_KEY");async function post(path, body, credential = serverKey) {  const response = await fetch(new URL(path, baseUrl), {    method: "POST", redirect: "error", signal: AbortSignal.timeout(10000),    headers: {      Authorization: `Bearer ${credential}`, "Content-Type": "application/json",      "X-Indiana-Project": projectId, "X-Indiana-Environment": "sandbox",    },    body: JSON.stringify(body),  });  const result = await response.json();  if (!response.ok) throw new Error(`${response.status} ${result.error?.code ?? "HTTP_ERROR"} requestId=${result.requestId ?? "unknown"}`);  return result;}// Use an ID verified by your own login system.const { customer } = await post("/api/v1/customers", {  externalUserId: required("INDIANA_VERIFIED_USER_ID"),});const { customerToken } = await post("/api/v1/customer-sessions", { customerId: customer.id });const { holdings } = await post("/api/v1/customer-holdings", {}, customerToken);console.log({ customerId: customer.id, balances: holdings.balances });

3. 接入你的登录系统

实际应用把前两次请求放在自己的后端会话接口:验证登录 → 使用稳定 user.id 识别 Customer → 只返回 customerToken / expiresAt。未登录返回 401,不能接受浏览器任意指定 Customer ID。

相关:复制 Next.js HTTP 接入文件

4. 连接 Web 页面

在 SDK 接入页添加网站 Origin,精确匹配协议、域名和端口。浏览器从自己的会话接口获取 Token,再读取 customer-holdings。Token 仅放内存;换号或登出时取消请求、清空旧状态。

完成标准

匿名会话请求返回 401;登录后读到自己的 holdings;浏览器没有 Server Key;切换账号不显示旧数据。读取供展示,真正执行业务前仍需服务端授权与原子消费。

常见问题与下一步

检查顺序
结果处理
UNAUTHENTICATED先区分宿主未登录与 Indiana 凭据失败。检查 Key;Token 过期则重新签发。
FORBIDDEN检查当前请求的权限与浏览器 Origin。
SCOPE_MISMATCHKey、App ID、环境和前后端配置必须一致。
balances: []连接成功。配置 Feature 与免费默认 Product,或通过独立购买取得持有,无需 Funnel。

检查顺序

  • UNAUTHENTICATED

    处理
    先区分宿主未登录与 Indiana 凭据失败。检查 Key;Token 过期则重新签发。
  • FORBIDDEN

    处理
    检查当前请求的权限与浏览器 Origin。
  • SCOPE_MISMATCH

    处理
    Key、App ID、环境和前后端配置必须一致。
  • balances: []

    处理
    连接成功。配置 Feature 与免费默认 Product,或通过独立购买取得持有,无需 Funnel。

相关:理解 Product、Feature 与 Entitlement

相关:接入用量与消费

相关:按错误码排查