Credits
Credits purchase, usage, and balance flow for AI usage.
Credits
Credits provide a predictable, ledger-backed usage model for AI workloads. This system supports free grants, paid packages, synchronous consumption, and async reservations.
Concepts
- Balance:
available(spendable) +reserved(held for async tasks). - Grants: credit buckets with
remainingand optionalexpiresAt. - Holds: temporary reservations for async jobs.
- Ledger: immutable audit log for every balance change.
Flow Overview
flowchart TD
A[User hits credits endpoint] --> B{Free grant exists?}
B -->|No| C[Create free grant]
B -->|Yes| D[Return balance + data]
C --> D
D --> E[Purchase credits]
E --> F[Stripe Checkout]
F --> G[Stripe webhook /api/webhooks/stripe]
G --> H[Mark purchase paid]
H --> I[Create grant + update balance + ledger]
I --> D
D --> J[User invokes AI request]
J --> K{Sync or async?}
K -->|Sync| L[Consume credits]
K -->|Async| M[Reserve credits]
M --> N{Job complete?}
N -->|Success| O[Settle hold -> spend]
N -->|Failed| P[Release hold]
L --> Q[Update balance + ledger]
O --> Q
P --> QPurchase Flow
- User selects a package (Base/Standard/Premium).
- Server creates Stripe checkout session and a pending
credits_purchasesrecord. - Stripe webhook confirms payment.
- System writes:
credits_grants(new bucket)credits_balances(increase available)credits_ledger(purchase event)
Usage Flow
Sync usage
consumeCreditschecksavailableand deducts from grants (earliest expiry first).- On success: updates balance and ledger (type:
spend). - On failure: returns
HTTP 400with insufficient credits message.
Async usage
reserveCreditscreates a hold and moves amount fromavailabletoreserved.settleCreditsHold:- success: converts hold to spend (deducts from grants, ledger type
spend). - failed: releases hold (ledger type
release).
- success: converts hold to spend (deducts from grants, ledger type
Free Credits
Configured in src/config/credits.ts.
- Issued once per user when they first access credits endpoints.
- Stored as
credits_grantswithpackageId = "free". - Optional expiry via
expiresInDays.
Expiry Rules
- Expired grants are zeroed and removed from
available. - A ledger entry (type:
expire) is written for audit.
Data Model
credits_balances: per-user snapshot (available, reserved).credits_grants: issued credits with remaining + expiry.credits_purchases: paid packages (pending/paid/failed).credits_holds: async reservations (active/consumed/released/expired).credits_ledger: append-only audit trail.
API Endpoints
GET /api/credits/overviewGET /api/credits/balanceGET /api/credits/ledgerGET /api/credits/packagesPOST /api/credits/purchasePOST /api/credits/consumePOST /api/credits/holdPOST /api/credits/hold/settlePOST /api/credits/grant(admin)
User Page
/dashboard/credits shows:
- Balance (available, reserved, total)
- Free grant status
- Paid purchases
- Ledger entries