/credit-metering

Usage credits on an append-only ledger with reserve, capture, release and refund.

Build·Usage → Credits·MIT
$npx skills add tushaarmehtaa/tushar-skills --skill credit-metering -g -a claude-code -y

Then type /credit-metering in Claude Code, or describe the task and let it pick the skill.

What you get back recorded run · 10 Oct 2026

claude · tallyroom

Using /credit-metering
  • 10 same-ID requests → 1 charge
  • 30 scans vs 5 credits → 5 run
  • 25 tests pass
Plus gets 50 scans a month, top-ups add 100, and a retry is charged once.
Claude Code 2.1.295·7m 04s·21 files changed
  • Scan credits are built: Plus gets 50 scans per paid billing month, one scan costs one credit, people can buy a 100-scan top-up, and a double-click or retry is charged once. The OCR call is still a stub. All 25 tests pass against a local Postgres 16, next build succeeds, and I ran an end-to-end check through the real routes.
  • 30 simultaneous scans against 5 credits: exactly 5 succeed.
  • In the end-to-end run, 5 parallel requests with one scan ID produced one charge (one 409 "already running", four 200s), and a repeated webhook delivery returned duplicate.
  • There's no auth in the app. lib/auth.js returns the user from the DEV_USER_ID env var, and only outside production.
CaveatRan with test keys on a throwaway local Postgres; no real Stripe payment or top-up went through.

Input → output from the run

app/pricing/page.jsx before
const rows = [
  ["Groups", "1", "Unlimited", "Unlimited", "Unlimited"],
  ["Members per group", "4", "20", "100", "Unlimited"],
  ["Receipt scanning", "—", "50 / month", "Unlimited", "Unlimited"],
  ["Multi-currency", "—", "✓", "✓", "✓"],
  ["Recurring bills", "—", "✓", "✓", "✓"],
  ["Export to CSV", "—", "—", "✓", "✓"],
  ["Priority support", "—", "—", "—", "✓"],
];
lib/scan-credits.js (new)
// Reserve one credit for a scan identified by the client's idempotency key.
// Returns { replay: true, request } for an already-succeeded key.
export async function reserveScan(userId, idempotencyKey) {
  return tx(async (c) => {
    const acct = await lockAccount(c, userId);
    await expireAllowanceIfDue(c, acct);
    await releaseStale(c, acct);

    const existing = (
      await c.query("select * from scan_requests where user_id = $1 and idempotency_key = $2", [userId, idempotencyKey])
    ).rows[0];
    if (existing?.status === "succeeded") return { replay: true, request: existing };
    if (existing?.status === "pending") throw new ScanInProgress("This scan is already running");

When to use it

Use when

Use when an app meters consumable usage with credits.

Skip it when

Skip it for plain subscriptions with nothing consumable to meter; payments-with-dodo covers billing itself.

The thinking behind it

Credits are money, so treat them like a ledger. Reserve, capture and refund cleanly, and usage stays fair even with retries and parallel requests.

Output contract from the skill's Output section

Report the denomination and policies, schema/migrations, ledger operations and invariants, protected usage paths, provider/product mapping, UI reconciliation, verification evidence, and remaining dashboard or production setup.

How it checks its own work from the instructions

  • Reserve, capture, and release flows are tested
  • Ledger and balance invariants hold under concurrent spend
  • Payment replay and out-of-order events are tested
  • Refunds, clawbacks, and promo races are tested

Requirements what it needs

Works in
Codex, Claude Code, Cursor
Needs
project files, terminal commands, network access

The instructions SKILL.md · 36 lines

Instructions & references

Back to overview ↑
On this page 4 sections
SKILL.md · MIT

Credit metering

Build credits as a financial state machine. Preserve existing denominations, billing semantics, and provider integrations.

Workflow

  1. Inspect backend/runtime, database/ORM, auth and tenant keys, current balance/ledger fields, payment provider, usage paths, retries, queues, and frontend state.
  2. Infer existing costs, grants, and packs from code. Ask only for unresolved commercial policy: denomination, per-action or measured cost, free/recurring grants, expiration/rollover, refund/clawback behavior, and overspend/debt policy. Never default to a new payment provider when one exists.
  3. Read database schemas, then implement only the matching database variant. Do not treat PostgreSQL, MySQL/PlanetScale, Prisma providers, and MongoDB as interchangeable.
  4. Use an append-only ledger with a unique idempotency key/external event ID. Update cached balance and ledger in one database transaction, or derive balance from the ledger when scale permits. Enforce positive input amounts and the chosen non-negative/debt rule in the database.
  5. Implement explicit operations:
    • grant for signup, subscription, promotion, or admin credit;
    • reserve before costly/concurrent work;
    • capture after measured success;
    • release on cancellation/failure;
    • refund or reverse linked to the original transaction;
    • expire/rollover when credits have lifecycle rules.
  6. Authenticate and authorize from server context. Never accept balance, price, pack value, or user identity from the browser. Map a server-owned product/price ID to the credit amount.
  7. Read payment providers only for the detected provider. Verify raw-body signatures, durably deduplicate events, and retry transient failures. Acknowledge before processing only after a durable queue/inbox write.
  8. Make promotions atomic. Use a redemption table with a unique (promo_id, user_id) constraint when one redemption per user is intended; update global usage and grant credit in the same transaction.
  9. Treat the UI balance as a projection. Reconcile after responses, account switches, multi-tab updates, refunds, and webhook grants. Optimistic display must not authorize work.

Verification

Test signup/recurring grant, reserve-capture, reserve-release, insufficient balance, variable final cost, duplicate request, concurrent spend, payment replay, out-of-order event, refund/clawback, promo race, account switching, and reconciliation after network failure. Assert ledger/balance invariants and run database concurrency tests plus repository lint/type/test/build commands.

Output

Report the denomination and policies, schema/migrations, ledger operations and invariants, protected usage paths, provider/product mapping, UI reconciliation, verification evidence, and remaining dashboard or production setup.

View on GitHub ↗
Claude app, ChatGPT and ZIP download

local coding agent required

This skill requires project files, terminal commands, and network access. Uploading it to a chat app does not provide equivalent execution.

ChatGPT Skills

This workflow needs a local coding environment or capabilities that a chat-only Skills upload does not provide.

Package details
Package
credit-metering/SKILL.md
Author
@tushaarmehtaa
Added
6 Mar 2026
Tags
creditsmeteringbillingpaymentsusageentitlements