No Fianto fee during the beta. Any fee comes with at least 30 days notice. See pricing
Use cases9 min read

Accept USDC for an AI app: monthly credits and one-off packs, without cards.

An AI app can take USDC with two Fianto products: a monthly price that grants a set number of credits each time a period is paid, and one-off checkout sessions that sell credit packs on top. Fianto charges fixed amounts only, with no metering or usage-based billing, so the credit balance lives in your own database and webhooks tell it when to add credits. You pay nothing per charge; on a 5.00 pack, a US card would cost you $0.445 at Stripe's published rate.

On this page
How do you bill an AI app in USDC when there is no usage billing?How should you price an AI plan and credit packs in USDC?How do monthly credits renew with a USDC subscription?How do you sell a one-off credit pack for USDC?Which webhook events should add, pause or stop credits?Should unused AI credits roll over or expire?What Fianto does not do for an AI appSourcesQuestions
TL;DR
  • 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:

ProductPriceCreditsCustomer pays per charge today
Starter, monthly9.00 USDC1,000 each period9.01 USDC: the price plus a flat 0.01 USDC network fee currently charged on subscriptions
Pro, monthly29.00 USDC4,000 each period29.01 USDC
Small pack, one-off5.00 USDC5005.00 USDC: one-off payments carry no network fee
Large pack, one-off20.00 USDC2,20020.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?

  1. Create the product and its monthly price in the dashboard. Prices are never edited: a new price is a new plan.
  2. From your server, create a checkout session with mode: 'subscription', the price's price_id, a fresh order_id and your user id as customer_reference. 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.
  3. The customer signs once. That transaction pays the first period and sets the cap per period: the price plus the fees.
  4. When the subscribe transaction finalizes you get subscription.created with period.index 0. Grant the allowance.
  5. Every 30 days, two minutes into the new period, Fianto collects the next charge. When it finalizes you get subscription.renewed with the next period index. Grant again.

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.

A webhook delivery log for one subscription: subscription.created on 13 October, subscription.renewed on 12 November and subscription.past_due on 12 December, each delivered. Two grants, then a pause.

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_id and, like every v1 POST, an idempotency key. With the SDK:

lib/credits/checkout.ts
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.paid arrives, not when the buyer comes back to success_url: the checkout shows success at confirmed, and the order turns paid only at finalized. The event carries your order_id, your metadata and the customer.reference 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?

EventWhat happenedWhat the ledger does
subscription.createdThe first period is paidGrant the allowance for period 0
subscription.renewedA renewal was chargedGrant the allowance for that period
subscription.past_dueA renewal failed for a reason that counts, such as too little USDCGrant nothing new; your choice whether the remaining balance stays usable
subscription.cancel_scheduledThe customer or you cancelled at period endNothing yet: the paid period runs out first
subscription.endedThe subscription is overStop the allowance
order.paidA pack payment finalizedGrant 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.paid 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:

app/api/webhooks/fianto/route.ts
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 overview

Should 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.

Sources
Questions

Questions about USDC billing for AI apps.

Can Fianto charge for AI usage, per token or per request?

No. Fianto charges fixed amounts only: a monthly or yearly price, or a one-off payment. Count usage in your app and sell credits in packs or as a monthly allowance.

What is the smallest credit pack I can sell for USDC?

A price or a session amount can be as low as 0.01 USDC, with up to 6 decimals. One-off payments carry no network fee, so the customer pays the pack price plus a Solana network fee under $0.01.

When should my app add the credits?

On the webhook. Add plan credits on subscription.created and subscription.renewed, and pack credits on order.paid, which arrives once the payment is finalized.

Can I offer a free trial on a USDC plan?

Fianto has no trials. You can grant trial credits from your own ledger and start the paid subscription when the user is ready.

What happens to credits when a renewal fails?

Fianto sends subscription.past_due and retries one hour, six hours and a day after the period boundary. Grant nothing for that period until subscription.renewed arrives; after the fourth counted failure the subscription ends.

Read next.

Use cases9 min read

Accept USDC for API and RPC plans: tiers, sessions and key webhooks

To accept USDC for API plans, make each tier a recurring USDC price, create a subscription checkout session when a signed-in account picks a tier, and let four webhook events drive the API key: issue it on subscription.created, extend it on subscription.renewed, decide on a grace rule at subscription.past_due, and revoke it on subscription.ended. Store the paid-until date from each event and check it on every request, so a missed webhook can never keep a key alive past what was paid. The customer approves once; Fianto collects every 30 or 365 days and sends the money straight to your wallet.

ComparePayments9 min read

Streaming payments vs per-period subscriptions: Superfluid and Fianto

Money streaming moves tokens from payer to payee continuously at a set rate per second, so the payee's balance grows every second until someone stops the stream or the payer's balance runs out; Superfluid does this on EVM networks with wrapped Super Tokens such as USDCx. A per-period subscription instead collects one fixed charge per billing period, which is how Fianto bills USDC on Solana: the customer approves once, and each 30- or 365-day charge is pulled within a cap. Streaming fits salaries, vesting and pay-as-you-go use; per-period billing fits a product sold by the month or year.

Stablecoins8 min read

Why price a subscription in USDC, not SOL: volatility, caps and trade-offs

Price a subscription in USDC because a recurring charge on Solana is capped by a fixed number of token units, and SOL's dollar value moves too much for a fixed number to stay a fair bill. On Coinbase, SOL closed at $202.55 on 14 October 2025 and $104.18 on 14 October 2026, with a low close of $62.15 on 6 June 2026, so 20 dollars took anywhere from 0.0987 to 0.3218 SOL in that year. A plan priced at 20.00 USDC asks the same amount every period; Fianto bills in USDC on Solana only.

Keep the ledger, let webhooks fill it.

Create one monthly price and one pack, then grant credits from the events.

New posts are announced on X and Discord.