Off-Ramp: Selling Crypto for Fiat in Mobile Apps
We've encountered this dozens of times: a client wants to withdraw cryptocurrency to a bank card, but the provider requires sending crypto first, with fiat arriving a couple of banking days later. Trust is the main barrier, solved by interface and transparency. In this article, we break down how we integrated off-ramp from Transak and MoonPay — turnkey, including KYC, SEPA, and push notifications. We assess your project — timelines from 5 to 12 days depending on complexity. Our experience: 5+ years in mobile fiat gateway development, 30+ integrations with payment providers. Over 5 years, we've launched 15+ off-ramp projects for fintech companies.
Why Off-Ramp Means Crypto Goes First
Unlike on-ramp, where the user first sees how much crypto they'll receive, off-ramp requires sending crypto to the provider's deposit address first. This creates an additional trust barrier. The interface must minimize anxiety.
Typical flow:
- User enters the crypto amount and bank account details.
- Provider issues a deposit address and confirms the rate (quote lifetime usually 15–30 minutes).
- The app sends crypto to the deposit address — typically via the built-in wallet send screen.
- Provider confirms receipt and initiates the fiat transfer.
KYC and Bank Account Verification
AML requirements for off-ramp are stricter. MoonPay and Transak require bank account verification via microtransactions (2 small debits for confirmation) or Open Banking (Plaid, TrueLayer).
The app must clearly inform the user about KYC timelines — verification can take 1–3 business days for the first off-ramp. Subsequent operations are instant after approval.
// iOS — launching Transak off-ramp widget var components = URLComponents(string: "https://global.transak.com")! components.queryItems = [ .init(name: "apiKey", value: transakApiKey), .init(name: "walletAddress", value: userWalletAddress), .init(name: "defaultCryptoCurrency", value: "ETH"), .init(name: "productsAvailed", value: "SELL"), // only off-ramp .init(name: "redirectURL", value: "myapp://offramp-callback"), .init(name: "themeColor", value: "000000") ] let safariVC = SFSafariViewController(url: components.url!) present(safariVC, animated: true) SEPA and Wire Transfer Support
For European users — SEPA Instant (credit within 10 seconds) and SEPA Credit Transfer (1–2 business days). For international — Wire (SWIFT, 2–5 days). Providers determine available methods based on user's country.
Transak supports SEPA for 30+ European countries. MoonPay supports SEPA, bank transfer for UK (Faster Payments).
Off-Ramp Provider Comparison
| Feature | Transak | MoonPay |
|---|---|---|
| SEPA Instant support | Yes (30+ countries) | Yes (eurozone) |
| Bank account verification | Microtransactions | Open Banking / microtransactions |
| Withdrawal time (SEPA) | 1–2 days | 1–2 days |
| User fee | 0.5–2% | 0.5–2% |
| Mobile SDK | URL widget | URL widget + native SDK |
Why Off-Ramp Requires Triple-Check of Transactions
Due to the irreversibility of crypto transfers, each transaction is checked three times: locally in the app, on the provider side, and on the blockchain. We add a confirmation screen with details (address, amount, rate) and a timer. If the user doesn't confirm within one minute, the quote expires and the rate recalculates. This reduces error risk and builds trust.
How to Speed Up Withdrawals with SEPA Instant?
SEPA Instant is not available for all countries and banks. To use it, the provider must support this system and have a partner bank in the target zone. Transak covers 30+ countries through a partnership with a UK bank. We recommend using SEPA Instant as the primary method for Europe — 10 seconds vs 1–2 days for standard SEPA. The interface should highlight this option as recommended.
Status and Notifications
An off-ramp transaction goes through several statuses: crypto_received → processing → fiat_sent → completed. Each transition triggers a push notification. The user should never guess the stage.
// Android — webhook status handler (server-side, pushed to device) when (webhookEvent.status) { "AWAITING_PAYMENT_FROM_USER" -> sendPush("Awaiting your transfer of $amount $currency") "PAYMENT_DONE_MARKED_BY_USER" -> sendPush("Crypto received, verification in progress") "ON_HOLD_PENDING_DELIVERY_FROM_TRANSAK" -> sendPush("Transfer initiated") "COMPLETED" -> sendPush("$fiatAmount ${fiatCurrency} sent to your account") "FAILED" -> sendPush("Transaction declined: $reason") } What's Included (Deliverables)
- Integration of one off-ramp provider (Transak or MoonPay) — 5 days.
- Multi-provider configuration with switching — 8–12 days.
- Includes: amount input UI, redirect handling via deep links, status retrieval via webhooks, push notification setup.
- Documentation of the flow and architecture.
- Support during App Store / Google Play release.
Timeline: 5 days for a single provider, 8–12 for multi-provider. Contact us to assess your project — receive a consultation on provider choice and architecture. We guarantee transparency and compliance with SEPA and App Store Review Guidelines (section 5.1).







