DEV Community

Alejandro Navarro Boned
Alejandro Navarro Boned

Posted on

How I Built a Credits-Based Billing System for AI SaaS Products

The Problem with Subscriptions for AI Products

If you're building an AI product, you've probably thought about billing. The obvious choice is subscriptions — $20/month, $50/month, etc.

But subscriptions don't work well for AI:

  • Heavy users eat your margin. One power user can cost you $100/month in API calls on a $20 plan.
  • Light users feel ripped off. They used the product twice and got charged $20.
  • Unpredictable costs. You can't forecast your API spend when usage varies wildly.

That's why every major AI company uses credits or tokens: OpenAI, Anthropic, Replicate, ElevenLabs.

The Solution: Credits-Based Billing

I built ShipAI, a Next.js boilerplate with credits billing baked in. Here's how the system works.

The RESERVE → STREAM → FINALIZE Pattern


typescript
// Step 1: Reserve credits BEFORE the AI call
// Uses SELECT FOR UPDATE for atomic locking
const reservation = await supabase.rpc('reserve_credits', {
  user_id: userId,
  amount: estimatedCost
});

// Step 2: Stream the AI response
const stream = await openai.chat.completions.create({
  model: 'gpt-4o',
  messages,
  stream: true
});

// Step 3: Count actual tokens and refund unused credits
await supabase.rpc('finalize_credits', {
  user_id: userId,
  reserved: estimatedCost,
  actual: calculateCost(inputTokens, outputTokens, model)
});
This pattern ensures:

Users are never overcharged (unused credits are refunded)
You never give away free API calls (credits are reserved first)
No race conditions (SELECT FOR UPDATE provides row-level locking)
Per-Model Pricing
Different models have different costs. ShipAI handles this automatically:

Model   Input (per 1K tokens)   Output (per 1K tokens)
GPT-4o  1 credit    3 credits
GPT-4o Mini 0.5 credits 1 credit
Claude Sonnet   1 credit    3 credits
Claude Haiku    0.3 credits 0.8 credits
Users choose their model, and the credit cost adjusts automatically.

Security Considerations
Credits are money. They need to be treated like financial transactions:

CHECK constraint: credits >= 0 — credits can never go negative at the database level
Idempotent webhooks: Stripe can send duplicate events. The add_credits function uses stripe_session_id as a unique key to prevent double-crediting.
Row-Level Security: Users can only read their own credit balance and transaction history.
Input validation: Max 100 messages per request, 32KB payload limit.
The Full Stack
ShipAI includes everything you need beyond just billing:

Next.js 15 with App Router
Supabase Auth (email, Google OAuth, magic links)
Stripe Checkout with pre-configured webhooks
Multi-model chat UI with streaming responses
Usage dashboard with token tracking
TypeScript + Tailwind CSS
One-click Vercel deploy
Try It
ShipAI is available for $69 (launch price, regular $149): Get ShipAI

If you're building an AI product and don't want to spend weeks on billing infrastructure, check it out. Happy to answer questions in the comments.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)