← Back to Next.js SaaS foundation team

Skill · Version 1.0.0

Usage, credits and quotas

Designs credit consumption and usage limits so simultaneous jobs and repeated requests do not silently distort a customer balance.

usage-metering-credits-quotas

Team members using this skill

See how it helps

When is it useful?

Use when your product charges by usage or offers prepaid credits with different expiration dates.

What does it help you do?

  • Tracks balance changes in a ledger and keeps credit batches and expiry order understandable.
  • Reserves capacity before long-running work and settles actual consumption according to the agreed policy.
  • Prevents duplicate usage reports and distinguishes hard limits from permitted overages.

Try asking this

Design a credit wallet for video exports with monthly and purchased credits. Show which credits are used first and how two simultaneous exports share the remaining balance. Start two exports just before monthly credits expire. Apply the agreed spending order, reserve once per export and explain remaining purchased and expiring balances.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Usage Metering, Credits & Quotas

Usage-based billing (API tokens, AI agent runs, emails sent, compute minutes, storage GB) and prepaid credit wallets are prime targets for race conditions (double-spending) and double-charging on retries. Design metering and quota enforcement with append-only ledgers and atomic concurrency control.

1. Append-Only Credit Ledger vs. Mutable Balance Column

Never manage prepaid credits or wallet balances solely with UPDATE wallets SET balance = balance - 10:

  • Double-entry / Append-Only Ledger (credit_ledger_entries):
    • Every balance change is an immutable row with id, tenant_id, idempotency_key (UNIQUE), entry_type (grant_subscription, grant_topup, promotional_bonus, usage_debit, reservation_hold, reservation_release, expiration, refund_reversal, manual_adjustment), signed amount, lot_id, and created_at.
    • Materialize current_balance on the wallet/lot row inside the same database transaction with a CHECK (balance >= 0) constraint so concurrent debits can never drive the balance negative.
  • Credit Lots & Expiration Order (FIFO by Expiry):
    • Subscription-included monthly credits (expire at current_period_end), promotional credits (expire on promo date) and purchased top-up credits (never expire or expire in 12 months) must be tracked in separate credit lots (credit_lots).
    • When consuming credits, deduct from the earliest-expiring eligible lot first (ORDER BY expires_at ASC NULLS LAST) so customers never lose expiring subscription credits while spending non-expiring top-up credits.

2. Reserve -> Commit -> Release for Long-Running Operations

When an operation takes seconds or minutes and has variable cost (e.g., an LLM/agent run, video render or batch export), checking if (balance > 0) before starting allows 20 concurrent requests to spend the same last credit:

  1. Reserve (Pre-Authorization Hold):
    • Before starting the job, atomically reserve the estimated or maximum budget (status: 'reserved', deducting from available_balance) with SELECT ... FOR UPDATE or an atomic conditional UPDATE ... WHERE available_balance >= :hold.
    • If insufficient balance, reject immediately (402 Payment Required / quota_exceeded) before incurring external compute/API costs.
  2. Commit (Settle Actual Usage):
    • When the operation finishes, record the actual metered cost (actual <= reserved, or capped/overage per policy) and release the unused portion of the reservation atomically.
  3. Release / Rollback on System Failure:
    • If the operation fails due to an internal system error or upstream outage before delivering output, release the reservation (status: 'released') so the user is not charged for a failed run.
    • Include a background sweeper for orphaned reserved holds whose worker crashed.

3. Metered Billing Aggregation & Overage Reporting

When reporting metered usage to a billing provider (e.g., Stripe Billing Meters / Usage Records):

  • Idempotent Usage Events: attach a deterministic idempotency_key (usage:${runId}:${stepId}) to every usage event so retried worker jobs never inflate the customer's metered bill.
  • Period Boundary Alignment: attributes usage events to the exact timestamp when the work occurred, respecting the subscription's billing period boundaries and grace window before invoice finalization.
  • Hard Cap vs. Soft Cap / Overage: enforce explicitly whether reaching 100% of plan quota blocks further usage (hard cap), triggers an automatic top-up (auto-recharge with a monthly safety ceiling!), or bills pay-as-you-go overage at period end.

Included files 1

  • SKILL.md