Managed billing: fiat users, credits, and sponsored gas
For many people the card is the only thing they have: no wallet, no exchange account, no ETH
for gas. The managed tier is the monetization layer on top of the self-custody rails, built for
exactly them: users pay by card or subscription, hold credits, and the platform sponsors their
gas and funds their escrow deposits. It runs as the billing service (npm run billing, port
8550) and changes nothing in the protocol.
The two doors
Two ways into the network differ only in who pays for what and whom the user trusts:
| Self-custody (default rails) | Managed tier (this) | |
|---|---|---|
| Who pays gas | the user | the platform, via the signature-gated AIOUMVerifyingPaymaster |
| Who funds escrow deposits | the user's wallet | the platform treasury, debited from credits |
| How value enters | crypto they already have | card top-up or subscription → credits |
| Platform revenue | protocol fee only | protocol fee + top-up fee (feeBps) + plan margin |
| Trust model | trustless | user trusts the platform (like any SaaS billing) — clearly a product, not the protocol |
The protocol never changes: managed users end up with normal on-chain sessions, vouchers and receipts. The managed tier is a service wrapped around the same rails, so a user can always graduate to self-custody. An agent does not know which door its owner came through; it opens the same sessions, signs the same vouchers and leaves the same receipts either way.
What the billing service does (npm run billing, port 8550)
The service keeps accounts and a credit ledger in SQLite, append-only and in cents. A
top-up credits amount − feeBps (for example, $20.00 at 250 bps credits $19.50), every gas
sponsorship and deposit is a ledger entry, and the balance is the sum, so each user has a full
audit trail.
Every account is on a plan, per-account parameters an admin can set. prepaid is
pay-per-credit, with defaults of a 2.5% top-up fee, daily gas and deposit caps, and a
low-balance threshold. subscription is, for example, "$50/mo for N credits":
monthlyCreditCents plus renewsAt, granted by the renewal sweep (POST /admin/renewals,
which you cron); price and quantity are per-deployment business settings. sponsored is the
free tier: no balance required, gas covered within a small daily cap, for growth and perks,
and the caps keep it un-farmable.
Gas sponsorship is POST /sponsor. The service verifies plan, balance and the rolling-24h
cap, signs an AIOUMVerifyingPaymaster sponsorship that is time-boxed and bound to the exact
UserOp, and debits the estimated gas cost, priced from ETH_USD_CENTS. The TS digest is
byte-identical to the contract's getHash, verified end to end through the EntryPoint.
Deposit funding is POST /fund-deposit: the treasury wallet transfers USDC to the user's
smart account against credits, so the fiat user never touches an exchange.
Notifications are the re-up prompt hooks: low_balance and depleted events, once per
threshold cross, surfaced on GET /account and optionally POSTed to a per-account
webhookUrl.
The admin API, behind bearer BILLING_ADMIN_TOKEN, creates accounts, issues grants (perks
and promos), changes plans, and runs the renewal sweep.
On the SDK side, set sponsorship: { url, token } in AIOUMConfig and openSession
becomes platform-sponsored automatically; clear refusal errors carry a topup flag for UX.
Session opens are gasless under sponsorship; the one-time deployment and authorization of a user's smart account is paid by the account owner.
The card-processor boundary
POST /webhooks/topup is the integration point for a card processor: the deployment verifies
the processor's webhook signature and calls the same code path with the payment amount. Out of
the box the endpoint is admin-gated, which also serves manual top-ups. Subscriptions map to the
processor's subscriptions driving /admin/renewals. Chargeback policy, KYC thresholds and
receipt emails are business decisions layered on the same ledger.
Keys & risk posture
Two keys run the service, and each is bounded. SPONSOR_SIGNER_KEY is hot, but it can only
authorize gas spend from the paymaster deposit, per-op and time-boxed, and rotation
(setSponsorSigner) instantly voids outstanding sponsorships. BILLING_TREASURY_KEY is the
USDC float for deposit funding; keep it small and topped from cold storage. Both keys are
required on a live chain (REAL_CHAIN); only the local development network falls back to
Anvil test keys. Caps are the blast-radius bound: a leaked account token can at most burn
that account's credits and caps, not the platform.
Walkthrough (packages/sdk/examples/billing-demo.ts)
The example runs the whole loop on the local development network. A card top-up of $50
credits $48.75 (fee $1.25). The treasury funds the user's smart account with $10 USDC. The user
then opens a gasless session through the verifying paymaster: billing signs the
sponsorship and debits ≈$10.21 of gas at the local network's gas price, and a paid call is
served. Finally a free-tier account opens a sponsored session with $0.00, and its second
request is refused by the daily cap. The full ledger and event trail for all of it is on
GET /account.
The top-up fee and plan margin the managed tier earns join the protocol fee in the treasury, in stablecoins.
Next: ZAI allocation and supply policy — where the token behind every stake comes from and how its supply is governed.