Billing
Meter AI features with a universal credit balance: per-action cost table, an atomic debit, owner bypass, and a clean 402 path that routes to pricing.
1 file
Description
Meter AI features with a universal credit balance: per-action cost table, an atomic debit, owner bypass, and a clean 402 path that routes to pricing.
Monetizing per-action usage: an AI generation, a heavy export, a compute job. The user holds a credit balance and each action costs credits.
Keep a single cost table so pricing is auditable and consistent:
export const CREDIT_COSTS = {
viewItem: 0, // free actions cost nothing
fillForm: 0,
aiGenerate: 3, // LLM actions cost a few
heavyExport: 8, // heavy compute costs more
} as const;
Free actions (viewing, form fills, alerts) cost 0. AI actions cost a small amount. Heavy compute costs more. Never charge for navigation.
Check and deduct in one transaction so two concurrent requests cannot both spend the last credit:
const ok = await db.transaction(async (tx) => {
const bal = await tx.getBalance(userId);
if (bal < cost) return false;
await tx.decrement(userId, cost);
return true;
});
if (!ok) return new Response("Insufficient credits", { status: 402 });
Gate the whole check behind an owner flag so internal accounts are never charged: if (user.isOwner) return runAction();. Read the flag from the user record, not a hardcoded id.
A 402 is a product moment, not an error. Catch it and route the user to /pricing (or a top-up modal) with context on what they tried to do. Do not let a user reach a screen where every action silently 402s.
Added 2026-07-01. Back to the Skill Library.

New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.