@credit-engine/sdk
v1.0.0
Published
Credit Engine SDK — AI credits for SaaS in 5 minutes
Downloads
24
Maintainers
Readme
@credit-engine/sdk
AI credits for SaaS in 5 minutes. Add usage-based billing to your AI product without building a credit system from scratch.
Install
npm install @credit-engine/sdkQuick Start
import { CreditEngine } from '@credit-engine/sdk';
const ce = new CreditEngine({
apiKey: 'ce_live_xxx', // or ce_test_xxx for sandbox
});
// Check balance
const { balance } = await ce.getBalance('cus_xxx');
// Consume credits (optimistic, async in persistent mode)
const { balance: remaining } = await ce.consume('cus_xxx', 5, 'AI: chat completion');
// Consume or throw if insufficient
await ce.consumeOrFail('cus_xxx', 10, 'AI: image generation');
// Clean up on shutdown
await ce.destroy();Configuration
const ce = new CreditEngine({
apiKey: 'ce_live_xxx', // Required. ce_live_ for production, ce_test_ for sandbox
baseUrl: 'https://...', // Custom API URL. Default: https://api.creditengine.dev
mode: 'auto', // 'persistent' | 'stateless' | 'auto'. Default: 'auto'
syncIntervalMs: 30000, // Cache sync interval (persistent mode). Default: 30s
gracefulDegradation: true, // Allow ops when API is down. Default: true
timeoutMs: 10000, // Request timeout. Default: 10s
maxRetries: 2, // Retry failed requests. Default: 2
onError: (err) => log(err), // Non-critical error callback
});Modes
The SDK has two operating modes, auto-detected by default:
Persistent (servers, Docker, Railway)
Maintains an in-memory cache for sub-millisecond balance checks:
getBalance()returns from cache (<1ms)consume()deducts locally and queues the API call (non-blocking)- Background sync every 30s corrects any drift
- If the API goes down, operations continue against the local cache
Stateless (Vercel, Lambda, Cloudflare Workers)
Every call goes directly to the API:
- No cache, no queue, no background processes
- ~50-100ms per call (one HTTP round-trip)
- Always consistent with the server
- Idempotency keys still work (server-side dedup)
Auto-detection: if VERCEL, AWS_LAMBDA_FUNCTION_NAME, NETLIFY, or CLOUDFLARE_WORKER env vars exist, stateless is used. Otherwise, persistent.
// Force a specific mode
const ce = new CreditEngine({ apiKey: 'ce_live_xxx', mode: 'stateless' });API Reference
getBalance(customerId, options?)
const { balance, customer_id, credit_name, breakdown } = await ce.getBalance('cus_xxx', {
includeBreakdown: true, // Include per-product breakdown
});consume(customerId, amount, description?, options?)
Deduct credits from a customer.
const { balance, transaction_id } = await ce.consume('cus_xxx', 5, 'AI: chat', {
idempotencyKey: 'req_abc123', // Prevent double-charging
metadata: { model: 'gpt-4' }, // Attached to the transaction
});consumeOrFail(customerId, amount, description?, options?)
Same as consume(), but throws InsufficientCreditsError if the customer doesn't have enough credits.
try {
await ce.consumeOrFail('cus_xxx', 100, 'AI: batch job');
} catch (err) {
if (err instanceof InsufficientCreditsError) {
console.log(`Need ${err.requested}, have ${err.currentBalance}`);
}
}add(customerId, amount, options?)
Add credits to a customer (topup, refund, adjustment).
const { balance, transaction_id } = await ce.add('cus_xxx', 500, {
type: 'topup', // 'topup' | 'adjustment' | 'refund'
description: 'Monthly credit grant',
metadata: { source: 'subscription' },
});getTransactions(customerId, options?)
Fetch paginated transaction history.
const { data, pagination } = await ce.getTransactions('cus_xxx', {
limit: 20,
offset: 0,
type: 'consumption', // Filter by type
});createTopUpSession(options)
Create a Stripe Checkout session for self-service credit purchases.
const { checkoutUrl, sessionId } = await ce.createTopUpSession({
customerId: 'cus_xxx',
successUrl: 'https://app.example.com/credits?success=true',
cancelUrl: 'https://app.example.com/credits',
});
// Redirect user to checkoutUrlgetUsageAnalytics(options?)
Get usage data as a time series.
const { data } = await ce.getUsageAnalytics({
period: 'last_30_days', // 'last_7_days' | 'last_30_days' | 'last_90_days' | 'current_month'
groupBy: 'day', // 'day' | 'week' | 'action'
customerId: 'cus_xxx', // Optional: filter by customer
});
// data: [{ day, consumed, added, net, transaction_count }]getTopConsumers(options?)
const { data } = await ce.getTopConsumers({ period: 'last_30_days', limit: 10 });
// data: [{ customer_id, total_consumed, total_added, transaction_count }]getActionBreakdown(options?)
const { data } = await ce.getActionBreakdown({ period: 'last_30_days' });
// data: [{ action, type, consumed, added, transaction_count }]getBurnRate(options?)
const { data } = await ce.getBurnRate({ days: 30 });
// data: { daily_avg_consumed, daily_avg_added, net_daily_burn, projection_days_remaining }getAnalyticsSummary(options?)
const { data } = await ce.getAnalyticsSummary({ period: 'last_30_days' });
// data: { total_consumed, total_added, net_change, total_transactions, active_customers, comparison: { ... } }destroy()
Flush pending operations and stop background processes.
await ce.destroy();pendingOperations
Number of queued deductions (persistent mode only).
console.log(ce.pendingOperations); // 0Idempotency
Prevent double-charging with idempotency keys. If the same key is sent twice, the server returns the original transaction instead of creating a new one.
const key = `user_${userId}_action_${actionId}`;
// Safe to retry — will only charge once
await ce.consume('cus_xxx', 5, 'AI: chat', { idempotencyKey: key });
await ce.consume('cus_xxx', 5, 'AI: chat', { idempotencyKey: key }); // No-op, returns same txError Handling
import {
CreditEngineError,
InsufficientCreditsError,
RateLimitError,
AuthenticationError,
} from '@credit-engine/sdk';
try {
await ce.consumeOrFail('cus_xxx', 100, 'expensive op');
} catch (err) {
if (err instanceof InsufficientCreditsError) {
// err.currentBalance, err.requested
} else if (err instanceof RateLimitError) {
// err.retryAfter (seconds)
} else if (err instanceof AuthenticationError) {
// Invalid API key
} else if (err instanceof CreditEngineError) {
// err.code, err.status, err.details
}
}Sandbox Mode
Use ce_test_ keys for development and testing. Sandbox data is fully isolated from production.
const ce = new CreditEngine({ apiKey: 'ce_test_xxx' });
// All operations affect sandbox data onlyTypeScript
Full type support with all response types exported:
import type {
CreditEngineConfig,
BalanceResponse,
ConsumeResponse,
AddResponse,
Transaction,
TransactionsResponse,
TopUpSessionResponse,
UsageAnalyticsResponse,
AnalyticsPeriod,
} from '@credit-engine/sdk';License
MIT
