权益、余额与用量
检查权益、上报用量、管理余额与 Entity,并为 AI 调用计费。
API v1更新于
检查权益并上报用量
执行功能前调用 checkEntitlement,完成后调用 trackUsage。数量都是十进制字符串。
1import { createIndianaServer } from "@tinkerlandai/indiana-sdk/server";2 3const indiana = createIndianaServer({4 baseUrl: process.env.INDIANA_API_URL!,5 apiKey: process.env.INDIANA_API_KEY!,6 scope: { projectId: process.env.INDIANA_PROJECT_ID!, environment: "sandbox" },7});8const featureId = process.env.INDIANA_FEATURE_ID!;9 10async function main() {11 // 1. Find or create the Customer for your signed-in user.12 const { customer } = await indiana.getOrCreateCustomer({ externalUserId: "user-42" });13 14 // 2. Check access before doing the work.15 const { check } = await indiana.checkEntitlement({16 customerId: customer.id,17 requirement: { internal_feature_id: featureId, quantity: "1", properties: {} },18 });19 if (!check.allowed) return console.log("blocked:", check.reason);20 21 // 3. Report usage after the work succeeds. Use your own event ID in production.22 const { receipts } = await indiana.trackUsage({23 customerId: customer.id,24 command: { internal_feature_id: featureId, quantity: "1", idempotencyKey: crypto.randomUUID() },25 });26 console.log("recorded:", receipts[0]?.accepted);27}28 29main().catch((error) => {30 console.error(error);31 process.exitCode = 1;32});
- 为每次用量生成并保存
idempotencyKey;结果未知时用同一个 key 重试,不会重复计费。 - HTTP 200 不代表已扣减:检查每条回执的
accepted 和 reason。
先预留、后确认
耗时任务可以先预留额度,完成后按实际数量确认,失败时释放。
1import { createIndianaServer } from "@tinkerlandai/indiana-sdk/server";2 3const indiana = createIndianaServer({4 baseUrl: process.env.INDIANA_API_URL!,5 apiKey: process.env.INDIANA_API_KEY!,6 scope: { projectId: process.env.INDIANA_PROJECT_ID!, environment: "sandbox" },7});8 9const feature = process.env.INDIANA_FEATURE_ID!;10 11// Hold credits before long-running work; keys are persisted per job.12export async function runJob(customerId: string, jobId: string, estimate: string) {13 const { receipt } = await indiana.mutateBalance({14 customerId,15 command: {16 operation: "reserve",17 internal_feature_id: feature,18 quantity: estimate,19 properties: {},20 idempotencyKey: `${jobId}:reserve`,21 expiresInSeconds: 600,22 },23 });24 if (!receipt.accepted) return { started: false as const, reason: receipt.reason };25 return { started: true as const, reservationId: receipt.id };26}27 28export async function finishJob(customerId: string, jobId: string, reservationId: string, actual: string | null) {29 const command = actual30 ? { operation: "confirm" as const, operationId: reservationId, quantity: actual, idempotencyKey: `${jobId}:confirm` }31 : { operation: "release" as const, operationId: reservationId, idempotencyKey: `${jobId}:release` };32 const { receipt } = await indiana.mutateBalance({ customerId, command });33 return receipt;34}
读取余额与账本
1import { createIndianaServer } from "@tinkerlandai/indiana-sdk/server";2 3const indiana = createIndianaServer({4 baseUrl: process.env.INDIANA_API_URL!,5 apiKey: process.env.INDIANA_API_KEY!,6 scope: { projectId: process.env.INDIANA_PROJECT_ID!, environment: "sandbox" },7});8 9export async function readBalances(customerId: string) {10 const { holdings } = await indiana.readHoldings({ customerId });11 const { ledger } = await indiana.readLedger({12 customerId,13 query: { type: null, from: null, to: null, after: null, limit: 20 },14 });15 return { holdings, ledger };16}
余额管理| 任务 | 方法 |
|---|
| 补发或扣回额度 | manageBalanceGrant, listBalanceGrants |
| 修正单个余额 | adjustBalance, readBalanceSource |
| 直接设定用量 | setUsage, readUsage |
| 批量上报用量 | submitUsageBatch, readUsageBatch |
| 对账单与统计 | readCreditStatement, readUsageAnalytics, readCreditAnalytics |
| 按工作区或设备计量 | manageUsageEntity |
| 席位分配 | readSeats, manageSeat |
余额管理
补发或扣回额度
- 方法
manageBalanceGrant, listBalanceGrants
修正单个余额
- 方法
adjustBalance, readBalanceSource
直接设定用量
- 方法
setUsage, readUsage
批量上报用量
- 方法
submitUsageBatch, readUsageBatch
对账单与统计
- 方法
readCreditStatement, readUsageAnalytics, readCreditAnalytics
按工作区或设备计量
- 方法
manageUsageEntity
席位分配
- 方法
readSeats, manageSeat
按 AI 调用计费
把中间件传给 AI SDK 的 wrapLanguageModel,每次调用按实际 token 用量计费。
ai-billing.tsTypeScript 1import {2 createAiUsageMiddleware,3 createConfiguredAiPricing,4 createIndianaServer,5 type AiUsageRecord,6} from "@tinkerlandai/indiana-sdk/server";7 8const indiana = createIndianaServer({9 baseUrl: process.env.INDIANA_API_URL!,10 apiKey: process.env.INDIANA_API_KEY!,11 scope: { projectId: process.env.INDIANA_PROJECT_ID!, environment: "sandbox" },12});13 14// Your own durable store for usage records and frozen quotes.15declare function saveUsageRecord(record: AiUsageRecord): Promise<void>;16 17export async function billingMiddleware(customerId: string, callId: string) {18 const featureId = process.env.INDIANA_AI_FEATURE_ID!;19 const pricing = await createConfiguredAiPricing(indiana, {20 internal_feature_id: featureId,21 customerId,22 });23 return createAiUsageMiddleware({24 pricing,25 client: indiana,26 modelId: "openai/gpt-4o",27 reasoning: "output",28 context: () => ({ customerId, internal_feature_id: featureId, idempotencyKey: callId }),29 persist: saveUsageRecord,30 });31}32// Pass the result to wrapLanguageModel({ model, middleware }) from the AI SDK.
- 每次模型调用使用新的
idempotencyKey,并在 persist 中保存记录,用于失败后恢复。 modelId 写成 provider/model;后端需要能访问 https://models.dev 获取模型价格。
相关接口
- 权益与商品展示 (4)
checkEntitlement, resolveOffering, resolvePaywall, readHoldings- 余额、用量与账本 (16)
readBalanceSource, adjustBalance, readUsage, setUsage, manageBalanceGrant, listBalanceGrants, manageUsageEntity, readUsageAnalytics, readCreditAnalytics, submitUsageBatch, readUsageBatch, readLedger, readCreditStatement, quoteBalance, trackUsage, mutateBalance- 席位 (2)
readSeats, manageSeat- AI 定价 (1)
readAiPricing
相关:路径、凭据与权限见全部接口