Billing
Owner Bypass for Founder Accounts
Use when a metered SaaS needs founder, team, or demo accounts to run every paid action for free, without scattering internal-account checks across the codebase. Covers an isOwner flag on the balance row, an env-backed owner list, and honoring the bypass inside the atomic debit so no call site has to remember it. Also use when a free account is still being charged, or a bypass was forgotten on a new route. If some accounts must not be billed, use this skill.
1 file
Description
Use when a metered SaaS needs founder, team, or demo accounts to run every paid action for free, without scattering internal-account checks across the codebase. Covers an isOwner flag on the balance row, an env-backed owner list, and honoring the bypass inside the atomic debit so no call site has to remember it. Also use when a free account is still being charged, or a bypass was forgotten on a new route. If some accounts must not be billed, use this skill.
name: owner-bypass-billing description: Use when a metered SaaS needs founder, team, or demo accounts to run every paid action for free, without scattering "if internal" checks across the codebase. Covers an isOwner flag on the balance row, an env-backed owner list, and honoring the bypass inside the atomic debit.
Owner Bypass for Founder Accounts
When to trigger
A credit-metered product where the founder, internal team, or demo accounts must never be charged, but every other user pays normally.
Put the flag on the user, honor it in the debit
Store an isOwner boolean on the balance row and check it inside the deduct function, not at each call site. Every metered action already routes through deduct, so one check there covers the whole app and no feature can forget it.
export async function deduct(clerkId: string, amount: number, reason: string) {
const info = await getBalance(clerkId);
if (info.isOwner) return { ok: true, balance: info.balance, owner: true }; // never charged
// ... atomic conditional decrement for everyone else ...
}
Back the flag with an env list so it survives a fresh row
Keep an OWNER_CLERK_ID env list of ids that are always owners. On balance lookup, if the id is in that list but the stored flag is stale (false), promote the row. This means a founder is free from the very first request, before anyone hand-sets a database flag, and a new environment inherits the bypass from config.
const envOwner = ownerEnvIds().has(clerkId);
if (envOwner && !row.isOwner) await db.update(balances).set({ isOwner: true }).where(eq(balances.clerkId, clerkId));
return { balance: row.balance, isOwner: row.isOwner || envOwner };
Report the bypass, do not hide it
Return an owner: true marker from the debit so the UI can show "free (owner)" and traces can record that no credits were spent. A silent bypass makes it hard to tell a free owner action from a billing bug.
Pitfalls
- Special-casing owners at each call site (
if (user.isOwner) return runAction()sprinkled everywhere) guarantees some path forgets it. Honor the flag once, inside the debit. - Hardcoding an owner's id in code ships it to the repo and cannot change per environment. Read the owner list from env and persist the resolved flag.
- Trusting a client-supplied "I am the owner" claim lets anyone go free. Derive ownership from the authenticated id against the server-side list only.
- Bypassing the debit but still writing a ledger entry double-counts. On owner bypass, skip both the charge and the ledger row and mark the result as owner.
Added 2026-07-01. Back to the Skill Library.

Get Smarter About AI Dev
New tutorials, open-source projects, and deep dives on coding agents - delivered weekly.