快速开始
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 接入中使用。
1# 复制你的 App → Sandbox → SDK 接入中的配置2INDIANA_BASE_URL=https://your-indiana-host.example3INDIANA_PROJECT_ID=your-project-id4INDIANA_SECRET_KEY=your-sandbox-server-key5 6# 浏览器可见;不包含 Secret Key7NEXT_PUBLIC_INDIANA_BASE_URL=https://your-indiana-host.example8NEXT_PUBLIC_INDIANA_PROJECT_ID=your-project-id
2. 建立身份并读取权益
保存完整脚本为 quickstart.mjs 后运行。三次请求属于同一 App / Sandbox;最后一次使用 Customer Token 读取自身数据,不传 customerId。
预期结果
输出 customerId 与 balances。同一作用域重复识别同一个 externalUserId 返回同一个 Customer。balances 为空仍表示接入成功,尚无符合条件的持有。
quickstart.mjsJavaScript 1// Node.js 22+,仅在可信后端执行,不输出 Key 或 Customer Token。2const required = (name) => {3 const value = process.env[name];4 if (!value) throw new Error(`Missing ${name}`);5 return value;6};7const baseUrl = required("INDIANA_BASE_URL");8const projectId = required("INDIANA_PROJECT_ID");9const serverKey = required("INDIANA_SECRET_KEY");10async function post(path, body, credential = serverKey) {11 const response = await fetch(new URL(path, baseUrl), {12 method: "POST", redirect: "error", signal: AbortSignal.timeout(10000),13 headers: {14 Authorization: `Bearer ${credential}`, "Content-Type": "application/json",15 "X-Indiana-Project": projectId, "X-Indiana-Environment": "sandbox",16 },17 body: JSON.stringify(body),18 });19 const result = await response.json();20 if (!response.ok) throw new Error(`${response.status} ${result.error?.code ?? "HTTP_ERROR"} requestId=${result.requestId ?? "unknown"}`);21 return result;22}23// Use an ID verified by your own login system.24const { customer } = await post("/api/v1/customers", {25 externalUserId: required("INDIANA_VERIFIED_USER_ID"),26});27const { customerToken } = await post("/api/v1/customer-sessions", { customerId: customer.id });28const { holdings } = await post("/api/v1/customer-holdings", {}, customerToken);29console.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_MISMATCH | Key、App ID、环境和前后端配置必须一致。 |
| balances: [] | 连接成功。配置 Feature 与免费默认 Product,或通过独立购买取得持有,无需 Funnel。 |
检查顺序
UNAUTHENTICATED
- 处理
- 先区分宿主未登录与 Indiana 凭据失败。检查 Key;Token 过期则重新签发。
FORBIDDEN
- 处理
- 检查当前请求的权限与浏览器 Origin。
SCOPE_MISMATCH
- 处理
- Key、App ID、环境和前后端配置必须一致。
balances: []
- 处理
- 连接成功。配置 Feature 与免费默认 Product,或通过独立购买取得持有,无需 Funnel。
相关:理解 Product、Feature 与 Entitlement
相关:接入用量与消费
相关:按错误码排查