Overview
An off-ramp converts cryptocurrency (USDC, USDT) into fiat currency (COP, MXN, USD). Users send crypto and receive local currency in their bank account.
Complete Off-Ramp Flow
Create User & Bank Account
Set up user profile and destination bank account
Get Quotation
Request price quote for crypto→fiat conversion
Create Ramp
Execute ramp with quote ID
User Sends Crypto
User transfers USDC/USDT to provided address
Conversion
KillB converts crypto to fiat
Fiat Delivered
Local currency sent to user’s bank
Implementation Example
const executeOffRamp = async (userId, bankAccountId, amount) => {
try {
// 1. Get quotation
const quote = await fetch('/api/v2/quotations', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
fromCurrency: 'USDC',
toCurrency: 'COP',
amount: amount,
amountIsToCurrency: false,
cashInMethod: 'POLYGON',
cashOutMethod: 'PSE'
})
}).then(r => r.json());
console.log(`You will receive: ${quote.toAmount} COP`);
// 2. Create ramp
const ramp = await fetch('/api/v2/ramps', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
quotationId: quote.id,
userId: userId,
accountId: bankAccountId,
externalId: `offramp-${Date.now()}`
})
}).then(r => r.json());
// 3. Show deposit address to user
const depositAddress = ramp.paymentInfo[0].address;
const depositNetwork = ramp.paymentInfo[0].network;
return {
rampId: ramp.id,
depositAddress: depositAddress,
depositNetwork: depositNetwork,
amountToSend: quote.fromAmount,
willReceive: quote.toAmount
};
} catch (error) {
console.error('Off-ramp failed:', error);
throw error;
}
};
Crypto Deposit Instructions
After creating the ramp, show users where to send crypto:
const showDepositInstructions = (ramp) => {
const paymentInfo = ramp.paymentInfo[0];
return (
<div>
<h3>Send {ramp.fromAmount} {ramp.fromCurrency}</h3>
<p><strong>Network:</strong> {paymentInfo.network}</p>
<p><strong>Address:</strong> {paymentInfo.address}</p>
<QRCode value={paymentInfo.address} />
<button onClick={() => copyToClipboard(paymentInfo.address)}>
Copy Address
</button>
<p>After sending, your {ramp.toCurrency} will be deposited to your bank within 1-3 hours.</p>
</div>
);
};
Bank Account Setup
Create bank account for receiving fiat:
Colombia (PSE)
Mexico (SPEI)
{
"type": "PSE",
"userId": "user-id",
"data": {
"firstName": "Juan",
"lastName": "García",
"accountNumber": "1234567890",
"bankCode": "0001",
"type": "savings",
"countryCode": "CO",
// ... other required fields
}
}
{
"type": "SPEI",
"userId": "user-id",
"data": {
"firstName": "María",
"lastName": "López",
"clabe": "012345678901234567",
"clabeType": "CLABE",
"countryCode": "MX",
// ... other required fields
}
}
Monitoring Deposit
Wait for user’s crypto deposit:
const waitForCryptoDeposit = async (rampId) => {
return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
const ramp = await getRamp(rampId);
if (ramp.status === 'CASH_IN_COMPLETED') {
console.log('Crypto received! Converting...');
clearInterval(interval);
}
if (ramp.status === 'COMPLETED') {
console.log('Fiat delivered to bank!');
clearInterval(interval);
resolve(ramp);
}
if (['FAILED', 'CANCELED'].includes(ramp.status)) {
clearInterval(interval);
reject(new Error(`Ramp ${ramp.status}`));
}
}, 15000); // Check every 15 seconds
});
};
Refund Instructions
Provide fallback address in case of issues:
{
"quotationId": "quote-id",
"userId": "user-id",
"accountId": "bank-id",
"refundInstructions": {
"network": "POLYGON",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"asset": "USDC"
}
}
If the off-ramp fails, crypto will be refunded to this address.
Next Steps