50% discount on fees for your first $1,000 in transactions!
50% discount for your first $1,000!
Back to the list

How to add fiat payouts to a crypto wallet app

Maria Sirotkina

A fiat payout (also called an off-ramp) lets a wallet user convert crypto into traditional money and send it to a bank account, debit card, or local payment rail. To add fiat payouts to a crypto wallet app, you need three building blocks: a regulated money transmitter, a quote and execution API, and a KYC layer. The Spritz SDK provides all three through a single set of REST endpoints, live in the United States and globally, with a typical integration time of one to two weeks. fomo, a Benchmark-backed trading app, used the Spritz SDK to enable $2M+ in fiat withdrawals for 4,000+ users in under two weeks of engineering work.

Diagram showing fiat payout flow from a user's crypto wallet through the Spritz SDK to a bank account via ACH or SEPA

A fiat payout (also called an off-ramp) lets a wallet user convert crypto into traditional money and send it to a bank account, debit card, or bill payment. To add fiat payouts to a crypto wallet app, you need three building blocks: a regulated money transmitter, a payment request API, and a KYC layer. The Spritz SDK provides all three through a single TypeScript client, with a typical integration time of one to two weeks. fomo, a Benchmark-backed trading app, used the Spritz SDK to enable $2M+ in fiat withdrawals for 4,000+ users in under two weeks of engineering work.

Download the off-ramp one-pager (PDF) for the full coverage matrix, pricing model, and integration timeline in one page.

What a fiat payout actually means inside a wallet app

A fiat payout is the moment a user stops holding crypto and starts holding money in their bank. The crypto is sold for a stablecoin or USD value, the value is settled with a regulated payments partner, and the funds arrive in the user's destination account on a real-world rail such as ACH or debit-push. Wallet apps typically expose this as a withdraw or cash-out action; the SDK underneath handles quoting, signing, settlement, and reporting.

Three integration models exist. Each trades user-experience control for speed.

ModelWho owns the UXWho owns complianceTime to shipBest for
Hosted widgetThe providerThe provider1 dayApps testing demand
White-label SDKYouThe provider1 to 2 weeksWallets and trading apps owning the brand
Direct APIYouYou and the provider4 to 8 weeksFintechs with internal compliance teams

Most modern wallets choose the white-label SDK because it preserves brand control without forcing the wallet team to take on money transmission risk directly. fomo took this path with the Spritz SDK and went live in under two weeks.

Why fiat payouts matter for a wallet in 2026

Stablecoin supply crossed $320 billion in April 2026, per DefiLlama. USDT and USDC together represent about 89% of circulating value. Users who hold those balances increasingly expect to spend them, not just trade them. Wallets without an off-ramp lose retention to wallets that offer one, and lose revenue to centralized exchanges that charge withdrawal fees for the same flow.

The fomo case shows the dynamic clearly. Before integrating the Spritz SDK, fomo had no native off-ramp; users could only withdraw to another wallet address. In Paul Erlanger's words:

“We did not have any good mechanism for users to withdraw via bank account. This led to a lot of user frustration, especially new users who deposit on the platform for the first time.”

— Paul Erlanger, Co-founder, fomo

After integration, support ticket volume around withdrawals dropped sharply, and 4,000+ users transacted $2M+ in bank withdrawals within the first launch window.

The broader market signal is even louder. Mastercard agreed in March 2026 to acquire BVNK for up to $1.8 billion, the largest stablecoin-infrastructure acquisition to date. Stripe paid $1.1 billion for Bridge in February 2025. The world's two largest payment networks are betting that stablecoin off-ramp infrastructure is not a niche; it is core payments plumbing for the next decade.

The off-ramp architecture: how it actually flows

A working off-ramp has four moving parts. The user holds the asset in their wallet. The Spritz SDK orchestrates KYC, account setup, and payment request creation. The user signs an on-chain call to the SpritzPay smart contract from their own wallet. Spritz, as the regulated counterparty, matches the on-chain transfer to the user's destination (bank, card, or bill) and routes the fiat to that destination over ACH or local rail.

The wallet team's job is to wire the user-facing surface (the Withdraw button, the destination picker, the confirmation screen) on top of these layers. Everything below the UI is provided by the SDK under existing licenses.

ComponentWhat it doesBuild it yourself?
KYC and identity verificationConfirms the user, screens against sanctionsNo, the SDK provides it via Persona
Payment request engineCreates a binding payment request tied to a destination accountNo, use the SDK
SpritzPay smart contractOn-chain settlement counterparty; the user signs a call to itNo, deployed and maintained by Spritz
Settlement and money movementRoutes USD to the user's bank, card, or billNo, requires MSB or EMI licenses
Frontend SDKRenders the withdraw flow inside your appYes, you build the UI on top of the SDK

Step-by-step integration with the Spritz SDK

The code below is from the @spritz-finance/api-client TypeScript client. Install with npm install @spritz-finance/api-client. The full reference is in the README.

Step 1: Initialize the client

The Spritz SDK uses two-tier authentication. An Integration Key identifies your application; a per-user API Key is returned when you create each user. Initialize server-side; never embed the Integration Key in a mobile or web client.

import { SpritzApiClient, Environment } from '@spritz-finance/api-client'

const client = SpritzApiClient.initialize({
    environment: Environment.Sandbox,
    integrationKey: 'YOUR_INTEGRATION_KEY_HERE',
})

Step 2: Create the user and run KYC

Create a user with their email. Spritz returns an API key scoped to that user; set it on the client. Then start KYC, which runs through Persona, either as a hosted URL or an embedded flow.

const user = await client.user.create({ email: 'user@example.com' })
client.setApiKey(user.apiKey)

const { verificationUrl, inquiryId, sessionToken } =
    await client.user.getVerificationParams()

// Option 1: open verificationUrl in a webview or browser tab
// Option 2: embed Persona's flow using inquiryId and sessionToken

Verification status updates are delivered via the verification.status.updated webhook event.

Step 3: Add the destination account

The user's destination can be a US or Canadian bank account, a debit card (Visa or Mastercard), or a bill (credit card, mortgage, utility). Add it before creating a payment request.

import { BankAccountType, BankAccountSubType } from '@spritz-finance/api-client'

const bankAccount = await client.bankAccount.create(BankAccountType.USBankAccount, {
    accountNumber: '123456789',
    routingNumber: '987654321',
    subType: BankAccountSubType.Checking,
    ownedByUser: true,
})

Step 4: Create the payment request

A payment request ties the destination account to an amount and the blockchain network the user will pay from.

import { PaymentNetwork } from '@spritz-finance/api-client'

const paymentRequest = await client.paymentRequest.create({
    amount: 500,
    accountId: bankAccount.id,
    network: PaymentNetwork.Ethereum,
})

Step 5: Get on-chain params and sign

The off-ramp settles via the SpritzPay smart contract. Get the transaction parameters from the SDK, then have the user sign the contract call from their own wallet.

const params = await client.paymentRequest.getWeb3PaymentParams({
    paymentRequest,
    paymentTokenAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC on Ethereum
})

// params.contractAddress, params.method, params.calldata, params.value, params.requiredTokenInput

const txHash = await wallet.send({
    to: params.contractAddress,
    data: params.calldata,
    value: params.value,
})

For Solana, use getSolanaPaymentParams instead. It returns a ready-to-sign VersionedTransaction.

Step 6: Listen for webhooks

Spritz emits webhooks at every payment state transition. Update your wallet UI from these events; do not poll. Webhooks are signed with HMAC SHA256 in the Signature header.

import { createHmac } from 'crypto'

app.post('/spritz/webhook', (req, res) => {
    const payload = req.body
    const expected = createHmac('sha256', WEBHOOK_SECRET)
        .update(JSON.stringify(payload))
        .digest('hex')

    if (expected !== req.headers['signature']) {
        return res.status(401).end()
    }

    if (payload.eventName === 'payment.completed') {
        notifyUser(payload.userId, payload.id)
    }
    res.status(200).end()
})

Key events: payment.created, payment.updated, payment.completed, payment.refunded, verification.status.updated, capabilities.updated.

A complete integration, including edge cases like failed bank verification or sanctioned addresses, typically takes one to two weeks of engineering time. fomo went from first line of code to production in under two weeks.

What fomo learned from going live

fomo is a trading app for non-experts. The team raised a $17M Series A from Benchmark in November 2025. The challenge for fomo was straightforward: trading volume was strong, but new users hit a wall the first time they tried to take money off the platform, because withdraw-to-bank did not exist.

DecisionWhat fomo didWhy it worked
Build vs buyBought via Spritz SDKFiat rails were not core to fomo's product roadmap
Hosted vs white-labelWhite-labelBrand consistency, native feel
Region 1United States ACHLargest user concentration
Time to first payoutUnder two weeksEngineering capacity preserved for trading features

“The Spritz team were professional, knowledgeable, and willing to work with us to create a custom native solution.”

— Paul Erlanger, Co-founder, fomo

MetricResult
Time from integration start to launchUnder 2 weeks
Users on the new withdrawal flow4,000+
Fiat withdrawn to bank$2M+
Support tickets about withdrawalsSharply down (per fomo)

“Before integrating Spritz, we only had the option of withdrawing to another wallet address. The impact for users who are not crypto-native is night and day.”

— Paul Erlanger, Co-founder, fomo

Full case: fomo x Spritz SDK case study.

Coverage: what your users can actually do

The matrix below reflects the documented Spritz SDK surface as of May 14, 2026.

DirectionAccount typesNetworks
Off-rampUS bank account, US debit card, US bills, CA bank account8 networks (see token table)
On-rampVirtual accounts (ACH and wire) plus ACH direct debit to SolanaEthereum, Polygon, Base, Arbitrum, Avalanche, Optimism, Solana, Tron
Bill payUS credit cards, mortgages, utilities, and moreSame as off-ramp
Virtual cardsUS virtual debit card, crypto-fundedAll supported networks

Stablecoin coverage per network is documented in the SDK reference. The current matrix:

NetworkTokens
EthereumUSDC, USDT, DAI, USDP, PYUSD
PolygonUSDC
BaseUSDC
ArbitrumUSDC
AvalancheUSDC
OptimismUSDC
SolanaUSDC, PYUSD
TronUSDT

Check if Spritz covers your target geographies. Talk to sales and we will respond within one business day with confirmed rails, supported tokens, and a sandbox key.

Compliance: what your team is responsible for

The split is simple: Spritz holds the licenses, and the integrator keeps Spritz informed about its user base and intended volumes.

ResponsibilityWallet appSpritz
Money transmitter / MSB licenseNot requiredHeld
KYC / KYB programNot requiredRun by Spritz
Sanctions screening (OFAC, EU, UK)Not requiredRun by Spritz
Travel Rule reportingPass user data via APIFiles reports
Acceptable use policyYour callSpritz aligns

This split is what makes the white-label SDK model viable for crypto-native teams without a banking org chart. For the full onboarding picture, see our KYB and compliance guide.

Build vs buy: a framework

If you are evaluating an off-ramp partner against a build path, the table below captures the realistic tradeoffs.

DimensionBuild in-houseLicense an SDK
Time to first payout9 to 18 months1 to 2 weeks
Licensing cost (US only)$750K to $2MIncluded
Headcount required4 to 8 (legal, compliance, ops, eng)0 to 1
Coverage at launch1 countryGlobal
Margin on each transactionHigher long-termSet your own markup
Speed of new rail launchQuartersDays
Engineering distraction from core productHighLow
Regulatory exposureHighLow

The honest answer for most wallet teams: license the SDK, set your own markup on top, and revisit the build decision once monthly off-ramp volume crosses $50M. fomo's choice to license rather than build is the textbook case; the team kept engineering focused on trading, not on money transmitter licensing.

Common pitfalls

Three failure patterns recur in wallet integrations. None of them are technical; they are all process or expectations issues.

The first is skipping the test suite for sanctioned wallet addresses. Engineering teams build the happy path quickly and assume the SDK will gracefully reject any flagged transaction. It will, but the in-app UX for “your transaction was blocked for compliance reasons” needs to be designed up front.

The second is showing the user a fiat quote before checking the on-chain transaction has confirmed enough blocks. Tie the UI state strictly to webhook events. A 10-second lag on a confirmation screen is recoverable; a refunded completed payout is not.

The third is hardcoding rail support per country. Coverage expands. The wallet should fetch supported rails dynamically from the SDK at app launch and cache them for the session.

Myths about crypto off-ramps

MythReality
Off-ramps require my company to become a money transmitterFalse. Spritz is the money transmitter. Your app remains a software provider.
Self-custody and off-ramps are incompatibleFalse. The user signs the SpritzPay contract call from their own wallet; Spritz only takes possession of the asset after that on-chain transfer settles.
Off-ramps are too slow for consumer UXFalse. US ACH settles same-day to 1 business day. Token delivery to settlement is on-chain (seconds on Solana and Base, minutes on Ethereum L1).
Off-ramp pricing is opaqueSpritz exposes the full cost stack so integrators can set their own markup. Transaction fees only apply once monthly volume exceeds $100.
Adding fiat off-ramp invites regulatory scrutiny on the walletThe opposite. The licensed counterparty model insulates the wallet from money-transmission obligations.

Glossary

TermDefinition
Off-rampConversion of crypto into fiat with delivery to a real-world destination
Payment requestA binding Spritz object linking an amount, network, and destination account; the on-chain equivalent of a “quote”
SpritzPayThe Spritz smart contract that the user signs a call to in order to settle a payment
ACHAutomated Clearing House, the US bank-to-bank payment rail
PersonaThe KYC provider the Spritz SDK uses for identity verification
MSBMoney Services Business, a US regulatory category for money transmitters
EMIElectronic Money Institution, the EU equivalent
Integration KeyThe credential that identifies your application to the Spritz SDK
User API KeyA per-user credential returned when you create a user; scopes SDK calls to that user

FAQ

What is a crypto off-ramp API?

A crypto off-ramp API is a server-side interface that converts cryptocurrency into fiat money and settles it to a user's bank account, card, or local payment rail. It typically exposes endpoints for KYC, payment request creation, on-chain settlement params, and webhook delivery.

How long does it take to add fiat payouts to a crypto wallet app?

Using a white-label SDK such as Spritz, a wallet team can ship fiat payouts to production in 1 to 2 weeks. fomo went live in under two weeks. Building the same capability in-house, including obtaining money transmitter licenses in the United States, typically takes 9 to 18 months and $750K to $2M.

Do I need a money transmitter license to offer fiat off-ramps?

Not if you partner with a licensed provider. Spritz holds the MSB and EMI licenses and acts as the regulated counterparty. The wallet app is the technology layer.

Which chains and tokens does the Spritz SDK support?

The Spritz SDK supports off-ramp from 8 networks: Ethereum, Polygon, Base, Arbitrum, Avalanche, Optimism, Solana, and Tron. Token coverage per network is documented in the SDK reference. USDC is supported on every network. Ethereum also supports USDT, DAI, USDP, and PYUSD; Solana supports USDC and PYUSD; Tron supports USDT.

How fast is the payout?

US ACH settles same-day to 1 business day. Token delivery to the SpritzPay settlement contract is on-chain, typically seconds on Solana and Base and minutes on Ethereum L1. Local rails in other markets settle on the same timelines they do for any fintech using that rail.

Can my users keep custody of their crypto until the moment of payout?

Yes. The Spritz off-ramp model is non-custodial up to the on-chain transfer. The user signs the SpritzPay contract call from their own wallet; Spritz only takes possession of the asset at the settlement contract address.

What is the difference between an on-ramp and an off-ramp?

An on-ramp converts fiat into crypto. An off-ramp converts crypto into fiat. The Spritz SDK supports both directions; for the on-ramp side, see our crypto onramp API guide.

What does the Spritz SDK cost?

Pricing depends on volume, geography, and which flows you turn on. The model is transparent: a clean fee structure with no rev share, so partners can set their own markup on top. Per-transaction fees apply once monthly volume exceeds $100. Request the one-pager for the full pricing model or talk to sales.

Has anyone shipped this on the Spritz SDK?

Yes. fomo, a Benchmark-backed trading app, integrated the Spritz SDK in under two weeks and processed $2M+ in fiat withdrawals for 4,000+ users. Full details in the fomo case study.

What happens if a payout fails?

Spritz emits a payment.refunded webhook event when a payment cannot be settled to the destination account. Surface the refund in the user's wallet UI so the user knows funds were returned.

Can users pay bills directly, or only withdraw to a bank?

Both. The same SDK supports bill pay (paying a third-party biller directly) and off-ramp (paying the user's own bank). Bills include US credit cards, mortgages, utilities, and more. See the crypto bill pay guide.

Does the Spritz SDK support virtual cards?

Yes. Integrators can issue crypto-funded virtual debit cards via client.virtualCard.create. Card numbers and CVVs are rendered securely via Spritz secure-element libraries for React and React Native.

Can integrators subsidize fees for their users?

Yes. The SDK supports per-transaction fee subsidies (gated feature). Set feeSubsidyPercentage and maxFeeSubsidyAmount on the payment request. Subsidized amounts are invoiced to the integrator separately.

Get started

Three paths from here, matched to where you are in your decision:

  1. Just exploring? Download the off-ramp one-pager (PDF). Coverage matrix, integration timeline, pricing model on one page.
  2. Comparing providers? Read the fomo case study and the self-custodial vs custodial guide.
  3. Ready to integrate? Talk to sales. We respond within one business day with a sandbox key, a coverage check, and a 30-minute walkthrough.

Most partners go from first call to live sandbox within 48 hours, and from sandbox to production in one to two weeks.

Heading 1

Heading 2

Heading 3

Heading 4

Heading 5
Heading 6

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

Block quote

Ordered list

  1. Item 1
  2. Item 2
  3. Item 3

Unordered list

  • Item A
  • Item B
  • Item C

Text link

Bold text

Emphasis

Superscript

Subscript

more from blog