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

Accept USDC for API and RPC plans, from tier prices to revoked keys.

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.

On this page
How do API and RPC providers bill in USDC today?How do you set up API tiers as USDC prices?How do you start a subscription from your API console?Which webhook events issue, limit and revoke an API key?How long should an API key keep working after a failed renewal?What happens when a customer upgrades, buys credits or leaves?What should you test before the first paying customer?SourcesQuestions
TL;DR
  • One product per tier with a monthly or yearly USDC price; one subscription session per sign-up, carrying your account id in customer_reference so every event names the account.
  • Gate keys on the current_period_end each event carries. A failed renewal is retried until about a day after the period ends, then the subscription ends.
  • There is no usage billing, trial or plan switching: sell overage as one-off payments and move tiers with a new subscription plus a cancel.

How do API and RPC providers bill in USDC today?

RPC providers already sell plans for USDC on Solana, usually as a payment the customer approves in their wallet or a wallet they connect for autopay. QuickNode announced on 5 December 2024 that "users can now pay for their monthly memberships using USDC on Solana", with the customer approving the transaction in a wallet at checkout (QuickNode blog). Helius invoices renewals in USDC on Solana with a payment link by default, and offers an optional autopay built on the Solana Foundation's Subscriptions program; when the wallet is short there is no automatic retry, and an unpaid project is "suspended after 3 days" (Helius billing docs, checked 15 October 2026).

Fianto, which publishes this post, runs the pull model on the same program: the customer approves a cap per period once, and each renewal is collected without a new signature. The rest of this post is the build on Fianto, from the dashboard to the key check in your API gateway; the questions to ask before choosing a gateway are in USDC payment gateway for SaaS. Neither provider above is a Fianto customer; they are here because their pages show how API billing in USDC works in practice.

How do you set up API tiers as USDC prices?

Set up each API tier as its own product with a recurring USDC price for each billing period you offer, created in the dashboard; the v1 API can read products and prices but not create them. One product per tier is our recommendation because the product name is what the checkout shows and what product_name carries on every event, so "Scale" reads better than one shared product name with three prices. An invented provider, Plinthwave RPC, might sell:

TierPriceBillingCustomer pays per charge today
Starter19.00 USDCMonthly (every 30 days)19.01 USDC
Pro49.00 USDCMonthly (every 30 days)49.01 USDC
Scale199.00 USDCMonthly (every 30 days)199.01 USDC
Scale, yearly1,990.00 USDCYearly (every 365 days)1,990.01 USDC

The extra 0.01 USDC is the network fee the customer pays with each charge today, on plans created since 6 October 2026; there is no Fianto fee during the beta, and after it the customer pays about 0.1 to 0.5% on top. You receive the full price and pay nothing. A price runs from 0.01 to 1,000,000 USDC and can never be edited: to change a tier's price, add a new price and point new sign-ups at its fian_price_ id.

How do you start a subscription from your API console?

Start a subscription from your console by creating a checkout session on your server with mode: 'subscription' and the tier's price id, then sending the signed-in user to the returned URL. Two fields do the bookkeeping: customer_reference comes back as customer.reference on every subscription event, and metadata (up to 20 keys) is copied onto the subscription.

lib/billing/start-plan.ts
import { Fianto } from '@fianto/sdk';

const fianto = new Fianto(); // reads FIANTO_APP_ID and FIANTO_APP_SECRET

const TIERS = {
  starter: process.env.FIANTO_PRICE_STARTER,
  pro: process.env.FIANTO_PRICE_PRO,
  scale: process.env.FIANTO_PRICE_SCALE,
};

export async function startPlan(accountId: string, tier: keyof typeof TIERS, signupId: string) {
  const priceId = TIERS[tier];
  if (priceId === undefined) throw new Error(`no price configured for ${tier}`);

  const session = await fianto.checkoutSessions.create(
    {
      mode: 'subscription',
      order_id: `signup_${signupId}`, // one per sign-up attempt, never reused
      price_id: priceId,
      customer_reference: accountId, // returns as customer.reference on every event
      metadata: { tier },
      success_url: 'https://console.plinthwave.example/billing/welcome',
      cancel_url: 'https://console.plinthwave.example/billing',
    },
    { idempotencyKey: `signup:${signupId}` },
  );
  return session.url; // send the customer here
}

Use a fresh order_id for each sign-up: once a subscription session with that id has completed, creating another answers 409 order_id_in_use. Calling again while the first session is still open returns that session with url: null, so keep the URL from the first call. Do not issue anything on the success page: the customer can close it after signing, and the payment only counts once Solana finalizes it.

Which webhook events issue, limit and revoke an API key?

Four subscription events are enough to drive an API key, and each one carries current_period_end, the moment the paid period runs out. Store that date as the key's paid-until, and let your API gateway compare against it on each request. Events then only move the date; they are not the only thing standing between an unpaid account and your RPC nodes.

app/api/webhooks/fianto/route.ts
import { Webhooks } from '@fianto/nextjs';
import { billing } from '@/lib/billing'; // your own data layer

export const POST = Webhooks({
  secret: process.env.FIANTO_WEBHOOK_SECRET,
  // Each billing call records event.id in the same database transaction and skips ids it has seen.
  onSubscriptionCreated: async (event) => {
    const sub = event.data;
    await billing.issueKey(event.id, {
      account: sub.customer.reference,
      subscription: sub.id,
      tier: sub.metadata.tier,
      paidUntil: sub.current_period_end,
    });
  },
  onSubscriptionRenewed: async (event) => {
    await billing.extend(event.id, event.data.id, event.data.current_period_end);
  },
  onSubscriptionPastDue: async (event) => {
    await billing.markPastDue(event.id, event.data.id, event.data.failure?.next_attempt_at);
  },
  onSubscriptionEnded: async (event) => {
    await billing.revokeKey(event.id, event.data.id, event.data.end_reason);
  },
});

The same callbacks exist in @fianto/express and @fianto/hono. Deliveries can repeat and arrive out of order, which is why every write is keyed on event.id and why a renewal only ever moves paid-until forward. Endpoint verification, signatures and the full event table are in grant and revoke access from webhooks; the API reference is subscriptions in the Fianto docs.

A webhook delivery log: subscription.created on 13 October 2026, subscription.renewed on 12 November, subscription.past_due on 12 December, each delivered.

How long should an API key keep working after a failed renewal?

An API key should keep working for at most about a day after a failed renewal, because that is how long Fianto keeps trying before the subscription ends. The attempts are fixed and measured from the period boundary:

AttemptWhenEvent if it fails
1Boundary + 2 minutessubscription.payment_failed and subscription.past_due
2Boundary + 1 hoursubscription.payment_failed
3Boundary + 6 hourssubscription.payment_failed
4Boundary + 24 hourssubscription.payment_failed, then subscription.ended with end_reason: "PAYMENT_FAILED"

Only wallet-side failures use up an attempt: insufficient funds, a removed approval, a frozen or a closed account. A success on any retry sends subscription.renewed and the subscription is active again. The period is never billed later, so a key you keep open during the retries is a day you may not be paid for.

Our rule of thumb for RPC: keep the key at full limits until the second attempt, then drop it to a free-tier rate limit until subscription.renewed or subscription.ended arrives. Fianto sends the customer no email, so the past-due event is your cue to tell them their wallet needs USDC before the next attempt in failure.next_attempt_at. The customer side is explained in failed renewals and retries.

What happens when a customer upgrades, buys credits or leaves?

Upgrading a tier

There is no plan switching or proration. An upgrade is a new subscription session for the higher tier, then POST /v1/subscriptions/{id}/cancel on the old one. With at: 'now' the old plan stops at once and the customer has paid for days they will not use; with at: 'period_end' both plans are live until the old period ends. If you owe a refund, you send USDC back from your own wallet: there is no refund API. A merchant cancel only stops Fianto from charging; it is final and changes nothing on Solana.

Selling extra requests

A subscription charges the same amount every period, so overage cannot be billed after the fact (paying per request is compared in x402 vs subscriptions for APIs). Sell credit packs up front as one-off sessions with mode: 'payment' and add the credits when order.paid arrives with your order id. One-off payments carry no network fee and no rent.

Leaving

The customer cancels in the portal at fianto.xyz/my. You get subscription.cancel_scheduled first and subscription.ended when the paid period runs out, so the key keeps working until the date they paid for. For what the Subscriptions program enforces underneath, see Solana subscriptions, and for the SaaS pitch, USDC billing for SaaS, API and RPC plans.

Checkout sessions, webhooks, the SDKs for Next.js, Express and Hono, and the CLI in one place.

Open the developer overview

What should you test before the first paying customer?

  1. Get the merchant account approved. Until then, API keys answer 401.
  2. Add the webhook URL to your application and answer the verification challenge. One application has one endpoint.
  3. Post a signed sample to your local route with npx @fianto/cli trigger subscription.created --forward-to http://localhost:3000/api/webhooks/fianto and check that a key is issued. Each trigger gets a fresh event id, so to test a repeat delivery, sign one payload file with fianto sign and post it twice: the second post must change nothing.
  4. Create a subscription session for each tier so its plan is on chain before a customer arrives.
  5. Subscribe to Starter from a wallet of your own with real USDC, then cancel it in the portal and watch the key stay live until the period end.

There is no test mode, so step five costs one real Starter period plus the fees and rent. That is cheaper than finding a key bug with a paying account. The other test tools are in testing a USDC integration when there is no test mode.

Sources
Questions

Questions about billing API plans in USDC.

Can I charge for an API subscription in USDC every month automatically?

Yes. The customer approves a cap once at checkout, and Fianto collects each renewal every 30 days on Solana without a new signature.

How do I link a Fianto subscription to an account in my system?

Send your account id as customer_reference when you create the session. It comes back as customer.reference on every subscription event, and metadata is copied onto the subscription too.

Can I bill RPC overage in USDC after the month ends?

No. Fianto charges a fixed amount per period. Sell extra requests up front as one-off payments and credit them on order.paid.

When should I revoke an API key after a missed USDC renewal?

At the latest on subscription.ended, which arrives about a day after the period ends if every retry fails. You can throttle it earlier, from the past-due event.

Do my API customers need SOL as well as USDC?

A little. Their wallet pays the Solana fee of the checkout transaction, under $0.01, and the account rent when they subscribe. Renewals need only USDC.

Read next.

Use cases9 min read

USDC payment gateway for SaaS: what to check before you pick one

Before a USDC gateway bills your SaaS plans, check five things first: whether renewals are pulled automatically or invoiced, who holds the money between your customer and you, who pays the fees, whether webhooks are signed and replayable, and what the customer needs to cancel. Fianto pulls renewals on chain within a cap the customer approved, sends the money straight to your wallet, charges you nothing, and signs every webhook. It has no free trials, no usage billing, no proration and no test mode, so check those against your plans before you start.

Solana10 min read

Solana Subscriptions and Allowances: the three delegation models, for merchants

Solana's Subscriptions and Allowances program gives a merchant three ways to take money from a customer's wallet later: a fixed delegation (a spending budget), a recurring delegation (a limit that resets each period, on terms the customer sets) and a subscription plan (billing terms the merchant publishes). Use a plan for fixed-price monthly or yearly products such as SaaS, API tiers and memberships. It is the only model Fianto runs, and Fianto operates the keys, the collection and the retries, so you run none of them.

Guides7 min read

Monthly or yearly: pricing a stablecoin subscription

On Fianto a monthly USDC plan renews every 30 days and a yearly plan every 365 days, so a 12.00 monthly plan charges 13 times in its first 365 days and is worth 146.00 USDC a year, not 144.00. Price the yearly plan against that figure: at 120.00 a yearly customer saves about 18%, and you collect the year up front. Because the merchant pays no fees on either, the yearly discount is a choice about cash and churn, not about saving processing costs.

Ship the key webhook before the pricing page.

Price the tiers, trigger a sample event, then take one real Starter payment.

New posts are announced on X and Discord.