Off-ramp (Sell Crypto)
The off-ramp flow lets your users convert cryptocurrency back into fiat and receive payouts via bank transfer, mobile money, or other local methods. The ONE SDK (@one_deploy/sdk v1.1.0) provides a drop-in widget for web and API methods for all platforms.
Widget Usage (Web)
OneOfframpWidget
The full-featured sell-crypto widget handles token selection, amount input, quote display, payout method selection, and transaction tracking.
import { OneOfframpWidget } from '@one_deploy/sdk';
function SellCryptoPage() {
return (
<OneOfframpWidget
defaultCryptoCurrency="USDT"
defaultFiatCurrency="USD"
defaultCryptoAmount="100"
allowedCryptoCurrencies={['USDT', 'USDC', 'ETH']}
allowedPayoutMethods={['bank_transfer', 'mobile_money']}
walletAddress="0xYourUserWalletAddress"
chainId={137}
onSuccess={(result) => {
console.log('Sale complete:', result.transactionId);
}}
onError={(error) => {
console.error('Sale failed:', error.message);
}}
onClose={() => {
console.log('Widget closed');
}}
theme="dark"
/>
);
}
OneOfframpWidgetProps
interface OneOfframpWidgetProps {
/** Default crypto token to sell */
defaultCryptoCurrency?: string;
/** Default fiat payout currency (ISO 4217) */
defaultFiatCurrency?: string;
/** Pre-filled crypto amount to sell */
defaultCryptoAmount?: string;
/** Restrict which crypto tokens the user can sell */
allowedCryptoCurrencies?: string[];
/** Restrict which fiat currencies are available for payout */
allowedFiatCurrencies?: string[];
/** Restrict available payout methods */
allowedPayoutMethods?: PayoutMethodType[];
/** Source wallet address holding the crypto */
walletAddress: string;
/** Source chain ID */
chainId?: number;
/** Called when the sale completes successfully */
onSuccess?: (result: OfframpTransaction) => void;
/** Called when the sale fails */
onError?: (error: { code: string; message: string }) => void;
/** Called when the user closes the widget */
onClose?: () => void;
/** Widget color theme */
theme?: 'light' | 'dark' | 'auto';
/** Override CSS class name on the root element */
className?: string;
}
type PayoutMethodType =
| 'bank_transfer'
| 'mobile_money'
| 'card_refund'
| 'paypal';
Preset Widgets
Lock the source token for a streamlined sell experience:
import {
OneSellUSDTWidget,
OneSellUSDCWidget,
OneSellETHWidget,
} from '@one_deploy/sdk';
function QuickSellPage() {
return (
<>
{/* Sell USDT to USD via bank transfer */}
<OneSellUSDTWidget
walletAddress="0xAbc..."
defaultFiatCurrency="USD"
allowedPayoutMethods={['bank_transfer']}
onSuccess={(tx) => console.log('USDT sold', tx)}
/>
{/* Sell USDC to EUR */}
<OneSellUSDCWidget
walletAddress="0xAbc..."
defaultFiatCurrency="EUR"
onSuccess={(tx) => console.log('USDC sold', tx)}
/>
{/* Sell ETH to NGN via mobile money */}
<OneSellETHWidget
walletAddress="0xAbc..."
defaultFiatCurrency="NGN"
allowedPayoutMethods={['mobile_money']}
chainId={1}
onSuccess={(tx) => console.log('ETH sold', tx)}
/>
</>
);
}
API Methods (All Platforms)
getOfframpQuote
Fetch a sell quote -- how much fiat the user will receive for a given amount of crypto.
import { OneEngineClient } from '@one_deploy/sdk';
const engine = new OneEngineClient({
apiKey: 'YOUR_API_KEY',
projectId: 'YOUR_PROJECT_ID',
});
const quote: OfframpQuote = await engine.getOfframpQuote(
'USDT', // cryptoCurrency
'500', // cryptoAmount
'USD', // fiatCurrency
'bank_transfer' // payoutMethod (optional)
);
console.log(quote);
// {
// quoteId: 'oq_def456',
// cryptoCurrency: 'USDT',
// cryptoAmount: '500',
// fiatCurrency: 'USD',
// fiatAmount: 496.25,
// exchangeRate: 0.9985,
// fee: { amount: '2.50', currency: 'USDT' },
// payoutMethod: 'bank_transfer',
// expiresAt: '2026-02-02T12:10:00Z',
// }
createOfframpTransaction
Initiate a sell transaction from a quote. The user must approve the on-chain token transfer as part of this flow.
const tx: OfframpTransaction = await engine.createOfframpTransaction({
quoteId: quote.quoteId,
walletAddress: '0xAbc...',
chainId: 137,
payoutDetails: {
method: 'bank_transfer',
bankName: 'Example Bank',
accountNumber: '1234567890',
routingNumber: '021000021',
accountName: 'Alice Smith',
},
metadata: { userId: 'user_42' },
});
console.log(tx);
// {
// transactionId: 'otx_ghi789',
// status: 'pending',
// cryptoAmount: '500',
// cryptoCurrency: 'USDT',
// fiatAmount: 496.25,
// fiatCurrency: 'USD',
// createdAt: '2026-02-02T12:00:00Z',
// }
getOfframpStatus
Check current status of an off-ramp transaction.
const status: OfframpTransaction = await engine.getOfframpStatus('otx_ghi789');
console.log(status.status);
// 'pending' | 'processing' | 'completed' | 'failed' | ...
getSupportedPayoutMethods
List payout methods available for a country.
const methods = await engine.getSupportedPayoutMethods('NG');
// [
// { type: 'bank_transfer', name: 'Bank Transfer', currencies: ['NGN'] },
// { type: 'mobile_money', name: 'Mobile Money', currencies: ['NGN'] },
// ]
// Omit country for global list
const allMethods = await engine.getSupportedPayoutMethods();
Types
interface OfframpQuote {
/** Server-generated quote identifier */
quoteId: string;
/** Crypto token being sold */
cryptoCurrency: string;
/** Amount of crypto to sell (string for precision) */
cryptoAmount: string;
/** Fiat currency the user will receive (ISO 4217) */
fiatCurrency: string;
/** Fiat amount the user will receive after fees */
fiatAmount: number;
/** Crypto-to-fiat exchange rate applied */
exchangeRate: number;
/** Fee breakdown */
fee: {
amount: string;
currency: string;
};
/** Payout method for this quote */
payoutMethod: PayoutMethodType;
/** ISO 8601 timestamp when this quote expires */
expiresAt: string;
}
interface OfframpRequest {
/** Quote ID from getOfframpQuote */
quoteId: string;
/** Wallet address holding the crypto */
walletAddress: string;
/** Chain ID of the source tokens */
chainId?: number;
/** Payout destination details */
payoutDetails: PayoutDetails;
/** Arbitrary metadata */
metadata?: Record<string, string>;
}
interface PayoutDetails {
/** Payout method type */
method: PayoutMethodType;
/** Bank name (for bank_transfer) */
bankName?: string;
/** Bank account number */
accountNumber?: string;
/** Routing / sort code */
routingNumber?: string;
/** Account holder name */
accountName?: string;
/** Mobile number (for mobile_money) */
mobileNumber?: string;
/** Mobile money provider */
mobileProvider?: string;
/** PayPal email (for paypal) */
paypalEmail?: string;
}
interface OfframpTransaction {
/** Unique transaction identifier */
transactionId: string;
/** Current status */
status: PaymentStatus;
/** Crypto amount debited from wallet */
cryptoAmount: string;
/** Crypto token symbol */
cryptoCurrency: string;
/** Fiat amount paid out */
fiatAmount: number;
/** Fiat currency code */
fiatCurrency: string;
/** Payout method used */
payoutMethod: PayoutMethodType;
/** On-chain transaction hash for the crypto debit */
txHash?: string;
/** Payout reference (bank reference, mobile money ID, etc.) */
payoutReference?: string;
/** Chain ID */
chainId: number;
/** ISO 8601 creation timestamp */
createdAt: string;
/** ISO 8601 last-updated timestamp */
updatedAt: string;
}
type PaymentStatus =
| 'pending'
| 'processing'
| 'completed'
| 'failed'
| 'expired'
| 'refunded';
Full Example: API-only Off-ramp
import { OneEngineClient } from '@one_deploy/sdk';
const engine = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});
async function sellUSDT(wallet: string, amount: string) {
// 1. Check supported payout methods for Nigeria
const methods = await engine.getSupportedPayoutMethods('NG');
console.log('Available methods:', methods.map((m) => m.type));
// 2. Get a quote
const quote = await engine.getOfframpQuote('USDT', amount, 'NGN', 'bank_transfer');
console.log(`You will receive ₦${quote.fiatAmount} (rate: ${quote.exchangeRate})`);
// 3. Create the sell transaction
const tx = await engine.createOfframpTransaction({
quoteId: quote.quoteId,
walletAddress: wallet,
chainId: 137,
payoutDetails: {
method: 'bank_transfer',
bankName: 'GTBank',
accountNumber: '0123456789',
accountName: 'Alice Adeyemi',
},
});
// 4. Poll for completion
let current = await engine.getOfframpStatus(tx.transactionId);
while (current.status === 'pending' || current.status === 'processing') {
await new Promise((r) => setTimeout(r, 5000));
current = await engine.getOfframpStatus(tx.transactionId);
}
if (current.status === 'completed') {
console.log(`Payout sent -- ref: ${current.payoutReference}`);
} else {
console.error('Sale failed:', current.status);
}
}
See Also
- Payments Overview
- On-ramp (Buy Crypto)
- Pay Widget -- unified payment component that includes off-ramp mode.