Finish identity integration and configure the stable Feature UUID plus a Product granting allowance. Reads need credits:read; backend consumption needs credits:consume.
Credits & usage
Read balances, consume atomically and reserve for asynchronous work.
SDK examples target the current API. Check matching SDK versions and HTTP alternatives
Before you start
Read balances
Configure current credit rates
Products & Billing → Entitlements → credit
Configuration illustration using example data; use the current Console for exact controls.
Separate quotes from execution
quoteBalance provides a read-only estimate. The trusted backend uses mutateBalance for consume, reserve, confirm, release or refund and retains the original idempotency key.
Check the resultFeature saves current configuration; use the Product terms returned after saving. Accepted usage retains its pricing facts; actual consumption uses atomic balance APIs.
const { holdings } = await grow.readHoldings();const { quote } = await grow.quoteBalance({ operation: "quote", internal_feature_id, quantity: "1", properties: {},});const { ledger } = await grow.readLedger({ type: null, from: null, to: null, after: null, limit: 50,});// For display only. Consume on your trusted backend.Browser reads use the current customer token and credits:read. Quantities are decimal strings. quoteBalance is a display estimate, not consumption authorization. Published catalog data determines pools, rates and sources.
Consume atomically
- Use a private backend key with credits:consume. Derive customerId from your trusted user mapping.
- Retry the same customer, operation, parameters and idempotency key to receive the original receipt. Changing parameters conflicts; a lost response must not cause a second charge.
- Rejected results are also idempotent. Use a new key for a new attempt after balance changes.
const { receipt } = await indiana.mutateBalance({ customerId: authenticatedIndianaCustomerId, command: { operation: "consume", internal_feature_id, quantity: "1", properties: {}, idempotencyKey: `job:${jobId}:consume`, },});if (!receipt.accepted) throw new Error(receipt.reason ?? "Credits unavailable");Reserve and finalize
Reserve before asynchronous work, confirm actual quantity on success, or release on failure. Reservations last at most 24 hours. Confirm, release and timeout allow one terminal state. Failed additional consumption rolls back finalization and keeps the hold pending. Refunds reference the original successful transaction and its historic pricing.
const { receipt: hold } = await indiana.mutateBalance({ customerId: authenticatedIndianaCustomerId, command: { operation: "reserve", internal_feature_id, quantity: "10", properties: {}, expiresInSeconds: 300, idempotencyKey: `job:${jobId}:reserve`, },});if (!hold.accepted) throw new Error("Insufficient credits");await indiana.mutateBalance({ customerId: authenticatedIndianaCustomerId, command: { operation: "confirm", operationId: hold.id, quantity: "8", idempotencyKey: `job:${jobId}:confirm`, },});// On failure use mutateBalance with operation release and operationId hold.id; omit quantity.HTTP operations
Use these operations with your HTTP integration. Each reference includes complete request/response fields and credential requirements; SDK snippets are an alternative when a matching SDK is available.
| Operation | HTTP | Permission |
|---|---|---|
| readHoldings | POST /api/v1/customer-holdings | entitlements:read |
| quoteBalance | POST /api/v1/balances/quote | credits:read |
| mutateBalance | POST /api/v1/balances/execute | credits:consume |
| readLedger | POST /api/v1/customer-ledger | credits:read |
Operation and permission
readHoldings
- HTTP
- POST /api/v1/customer-holdings
- Permission
- entitlements:read
quoteBalance
- HTTP
- POST /api/v1/balances/quote
- Permission
- credits:read
mutateBalance
- HTTP
- POST /api/v1/balances/execute
- Permission
- credits:consume
readLedger
- HTTP
- POST /api/v1/customer-ledger
- Permission
- credits:read
Check your result
Expected outcome
Verify consumption using its receipt. Use reserve → confirm/release for async work. Repeated requests must not deduct twice; retain the original idempotency key after a lost response.