Add Credits and Payments to a Lovable, Bolt or v0 App
Copy-paste prompts that add a credit balance, per-feature charging and Stripe checkout to an AI-built app, with the API key kept in a server or edge function secret.
By cred.diy Team

You'll add a credit balance, per-feature charging and a "Buy credits" button to an app built with Lovable, Bolt or v0 by pasting three prompts that call the Cred REST API from server-side code. The prompts are written so the AI builder puts your Cred API key in a server or edge function secret and never in browser code.
That last part needs watching. AI builders like to "simplify" by moving a fetch call into a React component. The prompts below forbid it, and the checklist in step 6 shows how to confirm the builder listened.
Prerequisites
- An app with sign-in, so the server knows each user's ID and email.
- A server side the builder can write to:
- Lovable: Supabase Edge Functions (Lovable Cloud or a connected Supabase project).
- Bolt: Supabase Edge Functions via its Supabase integration, or the server routes of the framework it scaffolded.
- v0: Next.js route handlers (
app/api/.../route.ts), deployed on Vercel.
- A cred.diy project with:
- a credit type (Dashboard → Credit Types, copy the Credit Type ID)
- a pricing tier (Dashboard → Pricing Tiers, "Copy ID")
- Stripe connected on the Payments page
- an API key (Dashboard → API Keys, starts with
sk_live_)
Where the API key goes
| Builder | Server code | Where the secret lives |
|---|---|---|
| Lovable | Supabase Edge Function | The project's Supabase secrets, read with Deno.env.get |
| Bolt | Supabase Edge Function or server route | Supabase secrets, or the host's environment variables |
| v0 | Next.js route handler | Vercel environment variable, without a NEXT_PUBLIC_ prefix |
Never paste the key into the chat itself, because chat history is stored with the project. Add it only through the platform's secrets or environment-variable settings, and give it to the builder as a name: CRED_API_KEY.
Step 1: Give the builder the real API docs
AI builders guess API shapes when they don't have the docs. Open /docs, click Copy docs for AI, and paste the result into the chat before the first prompt. The same Markdown is published at https://cred.diy/docs.md if your builder can fetch URLs.
Step 2: Paste the server function prompt
Create a server-side function named "cred". In Lovable or Bolt make it a Supabase
Edge Function; in v0 make it a Next.js route handler at app/api/cred/route.ts.
Rules:
- Read secrets CRED_API_KEY, CRED_CREDIT_TYPE_ID and CRED_PRICING_TIER_ID from the
server environment. Never put them in frontend code, and never in a variable
prefixed VITE_ or NEXT_PUBLIC_.
- Identify the user from the verified session on the server (the Supabase JWT, or
the app's auth). Never trust a user id, email or amount sent by the frontend.
- Lowercase the user's email before sending it.
- Cred base URL: https://eutdgemlrpvnxfkkpvlu.supabase.co/functions/v1/credits-api
- Send the key in an "x-api-key" header and "Content-Type: application/json".
Actions (the frontend posts { action, feature?, requestId? }):
- "welcome": POST /issue with body { user_id, user_email, credit_type_id, amount: 20,
reason: "Welcome credits" } and header Idempotency-Key: "welcome:<user id>".
- "balance": GET /balance?email=<email>&credit_type_id=<CRED_CREDIT_TYPE_ID>.
Return balances[0].balance, or 0 if balances is empty.
- "spend": look up the cost of the named feature in a server-side table
{ generate: 5 }. POST /deduct with body { user_id, user_email, credit_type_id,
amount, reason: feature, reference_id: requestId } and header
Idempotency-Key: "spend:<user id>:<requestId>".
If the response code is INSUFFICIENT_CREDITS or USER_NOT_FOUND, return HTTP 402.
If idempotent_replay is true, return HTTP 409 and do not run the feature again.
Otherwise return { balance: new_balance, transaction_id }.
Step 3: Add the secret
Add CRED_API_KEY, CRED_CREDIT_TYPE_ID and CRED_PRICING_TIER_ID where the table above says. In Lovable and Bolt with Supabase, that's the project's Edge Function secrets. In v0, it's the Vercel project's environment variables, which v0 also uses for external API keys. Redeploy if the platform asks you to.
Step 4: Paste the "charge for a feature" prompt
Before the Generate button runs its feature, call the "cred" function with
{ action: "spend", feature: "generate", requestId } where requestId is
crypto.randomUUID() created once per click (reuse it only when retrying that same
click). Only run the feature if the call succeeds.
If it returns 402, show "You're out of credits" with a "Buy credits" button.
Show the user's balance in the header using { action: "balance" } on load, and
update it from the balance returned by "spend". Call { action: "welcome" } once
after every sign-in; it is safe to repeat.
Behind this, Cred deducts atomically, so the balance can't go below zero even if two clicks land at once. The idempotency key means a network retry of the same click isn't charged twice.
Step 5: Paste the "buy credits" prompt
Add an action "checkout" to the "cred" function. It POSTs to
https://eutdgemlrpvnxfkkpvlu.supabase.co/functions/v1/hosted-checkout with the
same x-api-key header and body { user_id, user_email,
pricing_tier_id: CRED_PRICING_TIER_ID, success_url: "<app url>/credits?status=success",
cancel_url: "<app url>/credits" }. Return the "url" field from the response.
The "Buy credits" button calls this action and sets window.location.href to url.
Do NOT add credits on the success page; Cred adds them after Stripe confirms payment.
The hosted checkout returns { url, session_id, purchase_id }, where url is a Stripe Checkout page. After payment, Cred's Stripe webhook adds the tier's credits to that user. Redirect URLs must be https:// (http://localhost is allowed while developing). Otherwise Cred falls back to its own default pages.
Step 6: Check what the builder wrote
Spend two minutes on this before you ship:
- Search the frontend code for
sk_live_,CRED_API_KEYandcredits-api. None of them should appear outside the server function. - Open the browser's network tab and click Generate. You should see a request to your function and none to
credits-apiorhosted-checkout. - Read the function. Confirm the cost comes from a server-side table, the user comes from the session, and the
Idempotency-Keyheader is set on/issueand/deduct. - Test running out. Spend until the balance hits zero and confirm you get the 402 path, not an error page.
- Test buying. Complete a checkout and confirm the balance rises without any code on the success page adding credits.
Common mistakes
- The builder moves the Cred call into a component. If you see
fetch(".../credits-api/...")in a.tsxfile, ask for it to go back into the server function. - The key ends up as
VITE_CRED_API_KEYorNEXT_PUBLIC_CRED_API_KEY. Those prefixes exist to put values into the browser bundle (see Next.js and Vite). Rename the variable, rotate the key in Dashboard → API Keys, and update the secret. - The key is hard-coded in the function file. It's then in your repository's history. Rotate it and read it from the environment.
- Pasting the key into the chat. Treat a pasted key as leaked and rotate it.
- Crediting on the success page. Anyone can visit
/credits?status=success. Cred credits purchases from the payment webhook. - The frontend sends the amount. A user can edit any request their browser makes. Prices belong in server code.
- The function generates its own idempotency key on every attempt. Then a retry looks like a new charge. The key must come from the click, via
requestId.
FAQ
Can I tell the builder to install a Cred SDK? Not yet. The npm SDK isn't published, so have it call the REST API with fetch, as these prompts do.
Does this work if my app doesn't use Supabase? Yes. Any server code that can keep a secret works: a Next.js route, an Express server, a Cloudflare Worker. The Cred calls stay the same.
Can I sell monthly subscriptions instead of packs? Yes. Add billing: "recurring" to the checkout body with a tier whose billing type allows it. Without that field, checkout is a one-time purchase. See Subscriptions.
Will users keep their credits if I build a second app? Within the same Cred project, yes: the same email is the same wallet. See End users.
What does Cred cost me? Each API call uses 1 CRD platform credit. The pricing page has the packages.
Sources
- Lovable: Connect to Supabase (Edge Functions and secrets)
- Bolt: Supabase integration
- v0: External APIs; Vercel: Environment variables
- Next.js: Route handlers and Environment variables
- Vite: Env variables and modes
- Supabase: Edge Function secrets
- Stripe: Checkout
- cred.diy: Docs for AI (Markdown), Managing credits, Hosted checkout, Subscriptions, Authentication, End users, Pricing

Charge AI Agents per Call with x402 and Cred
Let AI agents prepay for your API in stablecoin through Cred's x402 purchase endpoint, then deduct credits on every call with idempotency keys and a spending-safe retry policy.

Launching a Second App? Keep Its Credit Wallets in the Right Project
An October 2026 launch checklist for choosing wallet boundaries, keeping project credentials aligned, and testing email-first identity without mixing balances.