One API call to take USDC payments.
Create a checkout with your order ID. The customer pays USDC to your wallet, and you get a signed webhook.
Simulate a payment to see two events.
// Its body shows here.
curl https://api.fianto.xyz/v1/checkout-sessions \ -u "$FIANTO_APP_ID:$FIANTO_APP_SECRET" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "mode": "payment", "order_id": "ACME-10231", "amount": "40.00", "description": "Pro, first month", "success_url": "https://acmerpc.com/billing/success", "cancel_url": "https://acmerpc.com/billing" }'
const url = 'https://api.fianto.xyz/v1/checkout-sessions'; const res = await fetch(url, { method: 'POST', headers: { 'Authorization': 'Basic ' + Buffer.from(`${process.env.FIANTO_APP_ID}:${process.env.FIANTO_APP_SECRET}`).toString('base64'), 'Idempotency-Key': crypto.randomUUID(), 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'payment', order_id: 'ACME-10231', amount: '40.00', description: 'Pro, first month', success_url: 'https://acmerpc.com/billing/success', cancel_url: 'https://acmerpc.com/billing', }), }); const session = await res.json(); // send your customer to session.url
import os, uuid, requests res = requests.post( "https://api.fianto.xyz/v1/checkout-sessions", auth=(os.environ["FIANTO_APP_ID"], os.environ["FIANTO_APP_SECRET"]), headers={"Idempotency-Key": str(uuid.uuid4())}, json={ "mode": "payment", "order_id": "ACME-10231", "amount": "40.00", "description": "Pro, first month", "success_url": "https://acmerpc.com/billing/success", "cancel_url": "https://acmerpc.com/billing", }, ) session = res.json() # send your customer to session["url"]
{
"id": "fian_cs_9Kd2Lm4Qx8Rt",
"object": "checkout_session",
"url": "https://checkout.fianto.xyz/c/…",
"mode": "payment",
"status": "OPEN",
"order_id": "ACME-10231",
"amount": "40000000",
"currency": "USDC",
"expires_at": "2026-09-17T15:01:02.000Z"
}
One request returns a checkout URL.
Send a price ID, or an amount and a description, with your own order ID.
- Call from your server. The secret stays there.
- Redirect the customer to the returned URL.
- They pay, your webhook fires and they land on your success URL.
Check the signature, then act on it.
Every event is signed with your endpoint's secret. Verify it on the raw body first.
import crypto from 'node:crypto'; // body is the raw request body, as a string export function verifyFianto(headers, body, secret) { const id = headers['webhook-id']; const ts = headers['webhook-timestamp']; // refuse anything older than five minutes const age = Date.now() / 1000 - Number(ts); if (Math.abs(age) > 300) return false; const raw = secret.replace('whsec_', ''); const key = Buffer.from(raw, 'base64'); const want = crypto.createHmac('sha256', key) .update(`${id}.${ts}.${body}`) .digest('base64'); const a = Buffer.from(want); const sigs = headers['webhook-signature'].split(' '); return sigs.some((part) => { const b = Buffer.from(part.split(',')[1] || ''); if (b.length !== a.length) return false; return crypto.timingSafeEqual(a, b); }); }
An order.paid for ACME-10231 arrives with "amount": "40000000", 40 USDC in base units. Run the check.
Pick one to see the result.
Events we send
| Event | When it fires |
|---|
No matching event.
npx @fianto/cli whoami npx @fianto/cli events list --type order.paid --limit 2 npx @fianto/cli events tail --forward-to http://localhost:3000/hooks/fianto npx @fianto/cli trigger test.event
Your webhooks, on your own machine.
@fianto/cli reads your recent events, forwards them to localhost while you build, and triggers signed test events.
- Forward real events to localhost, signed as Fianto signs them.
- Trigger any event with your webhook secret, to test a handler.
- Same app ID and secret as the API. Node 20.3 or later.
npx skills add https:// github.com/ fianto-xyz/skills --skill fiantoThen ask your agent: "Add Fianto checkout and webhooks to this app."
Let your AI agent build it.
The Fianto skill teaches Claude Code, Codex, Cursor and other agents how Fianto works, so they can add checkout and webhooks to your app the right way.
- One command installs it for the agents you use.
- Works with Claude Code, Codex, Cursor, Copilot, Gemini and Windsurf.
Developer questions.
Do I need a Solana node or on‑chain code?
No. You call HTTPS endpoints and receive webhooks. You never pay a network fee: the customer's wallet pays at checkout, and every subscription charge carries a flat network fee paid by the customer, 0.01 USDC today.
How do I know a webhook came from Fianto?
Each delivery carries an HMAC-SHA256 signature in Standard Webhooks format. Verify it, and refuse anything older than five minutes.
What if my endpoint is down?
We retry on the schedule above. Deduplicate on webhook-id and sort by timestamp.
Is the webhook the source of truth?
No, the transaction is. Each payment event carries its signature, so you can check it on Solana.
Can I test without real money?
No. There is no test mode and there are no test keys. Send a test event to check your endpoint, then take a small real payment.
Which tokens and networks can I accept?
USDC on Solana. Other tokens and networks are not accepted until marked live.
Get your first webhook today.
Send a test event to your endpoint. No Fianto fee during the beta.