On this page
- Monthly plan: grant credits on subscription.created and on each subscription.renewed, keyed by the period index so a repeated delivery grants nothing twice.
- Credit packs: a checkout session in payment mode, with a one-time price or an amount from 0.01 USDC; add the credits when order.paid arrives.
- Fianto has no metering, no overage billing, no trials and no proration: usage is counted in your app, and Fianto collects fixed amounts.
How do you bill an AI app in USDC when there is no usage billing?
You bill an AI app in USDC by selling credits in fixed amounts and counting usage yourself. Fianto knows two kinds of charge: a recurring price that renews every 30 days (monthly) or every 365 days (yearly), and a one-off payment. It never sees a token count, a request or an image, and it cannot charge for usage after the fact.
So the app keeps a credit ledger: a table of grants and spends per user, where the balance is the sum. Each model call spends credits. Fianto's job is to tell the ledger when money arrived, through signed webhooks. A subscription period that was paid becomes a grant of the plan's allowance; a paid pack becomes a grant of the pack's size.
This is the same shape most AI products already use with cards: a plan with a monthly allowance and top-ups when it runs out. What changes is how the money moves. The customer approves the plan once in their Solana wallet, each renewal is pulled within a cap they signed, and the USDC lands in your wallet in the same transaction.
How should you price an AI plan and credit packs in USDC?
Price plans and packs in round USDC amounts and let the credit count carry the margin. A Fianto price can be anything from 0.01 to 1,000,000 USDC with up to 6 decimals, so small packs are possible. Why the unit is USDC and not SOL is in why price a subscription in USDC, not SOL. An example catalogue, with what the customer pays per charge today:
| Product | Price | Credits | Customer pays per charge today |
|---|---|---|---|
| Starter, monthly | 9.00 USDC | 1,000 each period | 9.01 USDC: the price plus a flat 0.01 USDC network fee currently charged on subscriptions |
| Pro, monthly | 29.00 USDC | 4,000 each period | 29.01 USDC |
| Small pack, one-off | 5.00 USDC | 500 | 5.00 USDC: one-off payments carry no network fee |
| Large pack, one-off | 20.00 USDC | 2,200 | 20.00 USDC |
On top of that, the customer pays the Solana network fee of the transaction they sign, under $0.01, and no Fianto fee during the beta; after the beta, about 0.1 to 0.5% on top of the price. A first subscription also pays account rent in SOL: about 0.00144 SOL as of 15 October 2026 for the subscription account, returned when the customer reclaims it after the subscription ends, and about 0.00119 SOL once, on a wallet's first subscription, not returned. The checkout shows the exact live amounts before anyone signs.
You pay nothing per charge. Compare a US card at Stripe's published rate of 2.9% + 30¢ per successful domestic transaction (Stripe pricing, 15 October 2026): the 5.00 pack would cost you $0.445, almost 9% of the sale, and the 9.00 plan $0.56 a month. Small top-ups are where the fixed 30¢ hurts most. The full comparison is in USDC vs card fees.
How do monthly credits renew with a USDC subscription?
- Create the product and its monthly price in the dashboard. Prices are never edited: a new price is a new plan.
- From your server, create a checkout session with
mode: 'subscription', the price'sprice_, a freshid order_and your user id asid customer_. The first session ever created for a price also creates its plan on Solana, and the checkout shows the plan as preparing until it is on chain.reference - The customer signs once. That transaction pays the first period and sets the cap per period: the price plus the fees.
- When the subscribe transaction finalizes you get
subscription.withcreated period.0. Grant the allowance.index - Every 30 days, two minutes into the new period, Fianto collects the next charge. When it finalizes you get
subscription.with the next period index. Grant again.renewed
A month here is 30 days from the moment the customer subscribed, not the 1st to the 1st, so reset allowances on the webhook, never on the first of the month. Delivery is at least once and unordered, so make the grant idempotent: key it by subscription id plus period index, and a second delivery of the same event changes nothing.
How do you sell a one-off credit pack for USDC?
A credit pack is a checkout session in payment mode. Use a one-time price created in the dashboard when the pack is fixed, or send amount with a description when your server computes the price, for a custom pack size for example. Each session needs a new order_ and, like every v1 POST, an idempotency key. With the SDK:
import { randomUUID } from 'node:crypto';
import { Fianto } from '@fianto/sdk';
const fianto = new Fianto(); // reads FIANTO_APP_ID and FIANTO_APP_SECRET
export async function buyCredits(userId: string, credits: number, usdc: string) {
const orderId = `pack_${randomUUID()}`;
const session = await fianto.checkoutSessions.create(
{
mode: 'payment',
order_id: orderId,
amount: usdc, // for example '5.00'
description: `${credits} credits`,
customer_reference: userId,
metadata: { credits: String(credits) },
success_url: 'https://app.example/credits',
cancel_url: 'https://app.example/credits',
},
{ idempotencyKey: `pack:${orderId}` },
);
return session.url; // send the buyer here
}Add the credits when order. arrives, not when the buyer comes back to success_: the checkout shows success at confirmed, and the order turns paid only at finalized. The event carries your order_, your metadata and the customer. you sent, so the grant needs no lookup. One-off payments carry no network fee and need no rent. The field rules are in the docs page on checkout sessions.
Which webhook events should add, pause or stop credits?
| Event | What happened | What the ledger does |
|---|---|---|
subscription. | The first period is paid | Grant the allowance for period 0 |
subscription. | A renewal was charged | Grant the allowance for that period |
subscription. | A renewal failed for a reason that counts, such as too little USDC | Grant nothing new; your choice whether the remaining balance stays usable |
subscription. | The customer or you cancelled at period end | Nothing yet: the paid period runs out first |
subscription. | The subscription is over | Stop the allowance |
order. | A pack payment finalized | Grant the pack |
A past-due subscription is retried one hour, six hours and a day after the period boundary, four attempts in all, and ends after the fourth counted failure. A period that was never paid is never charged later, so never grant credits for it in advance. A subscription creates no order, so order. never fires for a plan. The subscription side of the route, with the Next.js SDK set up as in accepting USDC in a Next.js app:
import { Webhooks } from '@fianto/nextjs';
import { ledger } from '@/lib/credits/ledger'; // your own table
const ALLOWANCE: Record<string, number> = { 'Starter': 1000, 'Pro': 4000 };
export const POST = Webhooks({
secret: process.env.FIANTO_WEBHOOK_SECRET,
onSubscriptionCreated: async ({ data }) => {
await ledger.grantOnce(`${data.id}:${data.period?.index}`, data.customer.reference, ALLOWANCE[data.product_name]);
},
onSubscriptionRenewed: async ({ data }) => {
await ledger.grantOnce(`${data.id}:${data.period?.index}`, data.customer.reference, ALLOWANCE[data.product_name]);
},
onSubscriptionPastDue: async ({ data }) => {
await ledger.pauseAllowance(data.customer.reference);
},
onSubscriptionEnded: async ({ data }) => {
await ledger.endAllowance(data.customer.reference);
},
});Checkout sessions, signed webhooks, the SDKs and the CLI that sends sample events.
Open the developer overviewShould unused AI credits roll over or expire?
Let plan credits expire at the end of their period and let pack credits keep. The plan allowance is priced as a month of use, and rolling it over turns a subscription into a growing liability you have to serve later. A pack was paid for outright, and expiring it invites refund requests.
Refunds are manual either way: there is no refund API, so you send USDC back from your own wallet and remove the credits in your ledger. Cancelling is the customer's move, in the portal at fianto.xyz/my, and the plan runs to the end of the period they paid for. Removing the USDC approval in their wallet is not a cancel: the next renewal fails, the subscription goes past due, and it ends after the fourth failed attempt. What a customer sees while renewals are retried is in failed renewals and retries.
What Fianto does not do for an AI app
- No metering, usage-based or overage billing. Count usage in your app and sell packs up front. Billing by the second is a different model, covered in streaming payments vs per-period subscriptions.
- No free trials. Give trial credits from your own ledger without a Fianto charge.
- No plan switching or proration. An upgrade is a new subscription for the higher plan and a cancel of the old one; accepting USDC for API and RPC plans walks through both cancel options.
- No weekly or custom intervals: monthly is every 30 days, yearly every 365.
- No team seats on the buyer side and no cards. One wallet pays; it needs USDC on Solana and a little SOL.
- No test mode. Send sample events with the test-event endpoint or the CLI, then take one small real payment.
If your users are developers who already hold USDC, the rest of the SaaS pitch is on USDC billing for SaaS, API and RPC plans. If they are consumers who pay by card, keep cards for them and offer USDC beside it.