Open-source prepaid credits and usage billing for AI products.
Resvary gives AI applications a durable balance ledger and a safe request lifecycle:
grant or top up credits
→ reserve the maximum cost
→ execute the AI job
→ charge actual usage
→ release the remainder
→ issue an auditable usage receipt
The credit engine is payment-rail agnostic. The existing Arc Testnet invoice, memo proof, payment receipt, and signed webhook modules provide Resvary's reference external USDC funding path.
AI costs are known only after a model or tool finishes. A single balance -= cost update is not enough when requests retry, overlap, fail, or report usage late.
Resvary provides:
- USD-denominated credits with six-decimal integer arithmetic;
- multi-dimensional prices for tokens, seconds, images, jobs, or tool calls;
- atomic
reserve → commit/releaseoperations; - idempotency for grants, reservations, charges, and funding confirmations;
- immutable ledger entries and per-charge usage receipts;
- transactional outbox events using the existing
x-resvary-signatureformat; - in-memory and SQLite stores;
- Arc Testnet USDC top-ups through the reference funding adapter;
- an interactive Next.js demo and Express/Next.js starter generator.
npm install @resvary/sdk @resvary/sqliteimport { CreditLedger } from '@resvary/sdk/credits';
import { createSqliteCreditStore } from '@resvary/sqlite';
const credits = new CreditLedger({
projectId: 'my_ai_product',
store: createSqliteCreditStore({
path: '.resvary/resvary.sqlite',
}),
});
const meter = await credits.registerMeter({
key: 'llm_tokens',
dimensions: ['input_tokens', 'output_tokens'],
idempotencyKey: 'meter-v1',
});
const price = await credits.createPriceVersion({
meterKey: meter.key,
rates: [
{ dimension: 'input_tokens', unitSize: '1000', amount: '0.002' },
{ dimension: 'output_tokens', unitSize: '1000', amount: '0.008' },
],
idempotencyKey: 'price-v1',
});
await credits.grantCredits({
customerId: 'customer_123',
amount: '5',
idempotencyKey: 'signup-credit:customer_123',
});
const result = await credits.runMetered(
{
customerId: 'customer_123',
priceId: price.id,
estimatedUsage: { input_tokens: '2000', output_tokens: '1000' },
idempotencyKey: 'request_abc',
},
async () => {
const completion = await callYourModel();
return {
value: completion,
actualUsage: {
input_tokens: String(completion.usage.inputTokens),
output_tokens: String(completion.usage.outputTokens),
},
usageEventId: completion.id,
};
},
);
console.log(result.receipt.amount);
console.log(result.receipt.releasedAmount);
console.log(result.balance.availableAmount);If the provider throws, runMetered releases the full reservation. If provider execution succeeds but commit fails, the reservation stays open so the same operation can be retried safely.
Requires Node.js 24 because the persistent demo uses the built-in node:sqlite module.
npm install
npm run devOpen http://localhost:3000. The default flow is deterministic and does not require an AI API key. Optional OpenAI-compatible mode uses:
RESVARY_AI_BASE_URL=https://api.openai.com/v1
RESVARY_AI_API_KEY=
RESVARY_AI_MODEL=The old payment operations APIs remain under /api/receipts, /api/receipts/proof, and /api/webhook-inbox.
| Import | Responsibility |
|---|---|
@resvary/sdk/credits |
Accounts, grants, reservations, usage receipts, ledger, idempotency, outbox |
@resvary/sdk/pricing |
Meters, immutable price versions, integer usage rating |
@resvary/sdk/funding/arc |
Arc invoice/payment receipt to credit grant adapter |
@resvary/sqlite |
Persistent credit and payment receipt stores |
@resvary/sdk/receipts |
Stablecoin invoices, proofs, payment receipts, signed webhooks |
@resvary/sdk/middleware |
Compatible legacy x402 Express and Next.js paywalls |
UsageMeter and createBillingPlan remain available for compatibility but are deprecated. New integrations should use the credit ledger and versioned pricing.
- Money is never calculated with JavaScript floating point in the new engine.
- A project/customer account cannot have a negative available balance.
- SQLite mutations use
BEGIN IMMEDIATEand store the balance change, receipt, idempotency result, and outbox event together. - Credits are closed-loop product credits. Resvary does not support user-to-user transfer, cash-out, redemption, custody, tax invoices, subscriptions, or marketplace balances.
- SQLite is intended for local, single-node, and design-partner deployments. Postgres and a self-hosted HTTP service are later milestones.
- Arc funding is Testnet-first and is not a production money-flow claim.
- Prepaid credits
- Usage rating
- Architecture
- SQLite persistence
- Arc credit funding
- Migration from legacy billing
- Security and legal model
- Demo walkthrough
- Roadmap
npm install
npm run typecheck
npm run test --workspaces --if-present -- --reporter=dot
npm run buildThe project is Apache-2.0 licensed. See SECURITY.md before reporting a vulnerability.