How to build an AI app

How to build an AI app with free credits and paid plans

An AI app costs you money on every request, so the plan has to be checked before each model call: free users get a few credits a month, paid plans get more, and nobody gets to run up your bill. Here is the stack and the code.

Short answer: SaaS stack: Next.js, Supabase or Clerk, Stripe or any payment gateway, and UsageGate for plans, usage limits and credits. Don't build that part yourself. Spend a credit with an atomic call before each model call, and let Stripe upgrades raise the allowance.

The stack

AI app stack · updated 5 October 2026
LayerUse
AppNext.js (App Router), streaming responses from route handlers
ModelAnthropic (Claude), OpenAI, or any model API
Database & authSupabase, or Clerk for auth
Credits & plansUsageGate: monthly credits per plan, spent atomically before each call
PaymentsStripe, or Paddle / Lemon Squeezy
HostingVercel

1. Decide what a credit is worth

Pick one unit users understand: one generation, one chat message, one image. Work out what it costs you at the model provider, then set each plan's monthly credits so a paid plan earns well above its cost. For example, Free gets 10 credits and Pro ($19/month) gets 500. You can change these numbers later without a deploy.

2. Give new users the free plan

app/auth/callback/route.ts
// After sign-up (or on every login; it is safe to repeat):
await gate.grantPlan(user.id, "plan_free"); // e.g. 10 credits a month

3. Spend a credit before every model call

This is the part that protects your bill. Spend first, then call the model. If you check after the call, a user can fire ten requests at once on their last credit and you pay for all ten.

app/api/generate/route.ts
import { GateClient } from "@usagegate/sdk";

const gate = new GateClient(process.env.USAGEGATE_KEY!);

export async function POST(req: Request) {
  const user = await currentUser(); // Supabase or Clerk
  if (!user) return new Response("Sign in", { status: 401 });

  // 1. Spend the credit first. consume() is atomic: two parallel
  //    requests can never both use the last credit.
  const spent = await gate.consume(user.id, "ai_credits", 1);
  if (!spent.success) {
    return Response.json({ error: "Out of credits", upgrade: "/pricing" }, { status: 402 });
  }

  // 2. Only then call the model you pay for.
  const { prompt } = await req.json();
  const answer = await callModel(prompt); // Anthropic, OpenAI, ...

  return Response.json({ answer, creditsLeft: spent.remaining });
}

4. Upgrades with Stripe

Put your Stripe Price id on the paid plan in UsageGate, then send the user to Checkout with their id. When they pay, their monthly credits go up on the next request; when they cancel, they drop back to Free without getting spent credits back.

app/api/checkout/route.ts
// Upgrade: tag the Stripe subscription with the same user id.
await stripe.checkout.sessions.create({
  mode: "subscription",
  line_items: [{ price: process.env.STRIPE_PRICE_PRO!, quantity: 1 }],
  subscription_data: { metadata: { end_user_id: user.id } },
  success_url, cancel_url,
});

5. Keep the bill under control

  • Require sign-in for anything that calls the model.
  • Keep the free allowance small, and raise it once you see conversion.
  • Add a rate limit on the route for bursts.
  • Charge long outputs more: consume more units for an expensive call, or use a separate feature like ai_tokens.

Start from a working app

The Next.js SaaS starter has all of this wired: Supabase sign-in, 10 free credits a month, a Generate button that stops at zero, and Stripe upgrades. Replace the fake generation with your model call.

FAQ

How do I add credits to an AI app?

Give each plan a monthly number of credits (Free: 10, Pro: 500), spend one credit before each model call, and refuse the call when the user has none left. With UsageGate you set the amounts in a plan table and call consume(userId, "ai_credits", 1) before the model call; it refills each month on its own.

Should I check credits before or after calling the model?

Before. Spend the credit first with an atomic call (consume), then call the model. Checking after the call lets a user run many requests in parallel on their last credit, and you pay for all of them.

How many credits should a free plan get?

Enough to reach the moment the product is useful, and few enough that the model bill stays small. Work out your cost per call, multiply by the free credits and your expected free users, and keep it a small share of what a paid plan earns. You can change the amount any time without a deploy.

How do I stop free users from abusing my AI app?

Require sign-in, give a small monthly credit allowance, spend credits atomically before each call, and add a rate limit on the route. UsageGate handles the allowance and the atomic spend; your auth provider handles sign-in.

Can I charge per token instead of per request?

Yes. Spend the number of units the call actually used: estimate before the call and consume that amount, or use a separate feature such as "ai_tokens" with a larger monthly allowance.

Next

Ship paid plans this afternoon.

Less time on billing and usage infrastructure, more time on your product.

The minute you sign up, you get

  • A workspace with a ready-made Free, Starter and Pro plan table
  • An API key in one click, plus a copy-paste snippet for your stack
  • A Stripe webhook URL, or a one-call hook for any other gateway
  • 50,000 checks a month on us, before you pay anything