What is a Quotation?
A Quotation is a price quote for converting between currencies. It locks in an exchange rate for 30 seconds, allowing users to see exactly how much they’ll receive before committing to a transaction.
Quotations are required before creating any ramp. They ensure price transparency and protect against rate fluctuations.
How Quotations Work
Request Quote
Specify currencies, amount, and payment methods
Receive Rate
Get locked-in rate valid for 30 seconds
Show to User
Display exact amounts user will send/receive
Create Ramp
Use quotation ID to execute transaction at quoted rate
Creating a Quotation
Request:
{
"fromCurrency" : "COP" ,
"toCurrency" : "USDC" ,
"amount" : 100000 ,
"amountIsToCurrency" : false ,
"cashInMethod" : "PSE" ,
"cashOutMethod" : "POLYGON"
}
Response:
{
"id" : "quot-9f8e7d6c-5b4a-3c2d-1e0f" ,
"fromCurrency" : "COP" ,
"toCurrency" : "USDC" ,
"fromAmount" : 100000 ,
"toAmount" : 23.81 ,
"rate" : 4200.50 ,
"spotPrice" : 4180.25 ,
"expiresAt" : 1704657630000 ,
"cashInMethod" : "PSE" ,
"cashOutMethod" : "POLYGON"
}
const getQuote = async ( fromAmount , fromCurrency = 'COP' , toCurrency = 'USDC' ) => {
const response = await fetch ( 'https://teste-94u93qnn.uc.gateway.dev/api/v2/quotations' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
fromCurrency ,
toCurrency ,
amount: fromAmount ,
amountIsToCurrency: false ,
cashInMethod: 'PSE' ,
cashOutMethod: 'POLYGON'
})
});
const quote = await response . json ();
console . log ( `Rate: ${ quote . rate } , You receive: ${ quote . toAmount } ${ toCurrency } ` );
return quote ;
};
Quote Parameters
Amount Direction
The amountIsToCurrency flag determines which amount is fixed:
User specifies how much to send {
"fromCurrency" : "COP" ,
"toCurrency" : "USDC" ,
"amount" : 100000 ,
"amountIsToCurrency" : false
}
Result: “Send 100,000 COP, receive ~23.81 USDC”Use when: User wants to spend exact amount of fiatUser specifies how much to receive {
"fromCurrency" : "COP" ,
"toCurrency" : "USDC" ,
"amount" : 25 ,
"amountIsToCurrency" : true
}
Result: “Send ~105,000 COP, receive exactly 25 USDC”Use when: User wants to receive exact amount of crypto
Payment Methods
Specify both cash-in and cash-out methods:
Cash-In Methods (source):
PSE - Colombian bank payment
SPEI - Mexican bank transfer
TRANSFIYA - Colombian mobile wallet
ACH - US ACH transfer
WIRE - Wire transfer
POLYGON, SOLANA, etc. - Crypto networks
PRE_FUND - Pre-funded fiat
PRE_FUND_POLYGON, etc. - Pre-funded crypto
Cash-Out Methods (destination):
Same as cash-in, except no PRE_FUND options
Exchange Rates
Rate Components
{
"rate" : 4200.50 ,
"spotPrice" : 4180.25
}
spotPrice : Market rate from liquidity providers
rate : Final rate including KillB’s fees and margin
Calculation:
toAmount = fromAmount / rate
Spread = rate - spotPrice
Fee % = (spread / spotPrice) * 100
Rate Factors
Exchange rates are influenced by:
Market Rate - Current market price
Payment Method - Different methods have different costs
Volume - Larger transactions may get better rates
Network - Blockchain network affects fees
Customer Tier - Your customer’s negotiated pricing
Pre-funded accounts typically receive better rates due to reduced operational costs.
Quote Expiration
Quotations expire after 30 seconds to protect against market volatility.
Handling Expiration
async function createRampWithRetry ( quoteId , userId , accountId ) {
try {
const ramp = await createRamp ( quoteId , userId , accountId );
return ramp ;
} catch ( error ) {
if ( error . message . includes ( 'expired' )) {
// Get new quotation
const newQuote = await getQuotation ( /* params */ );
return await createRamp ( newQuote . id , userId , accountId );
}
throw error ;
}
}
Countdown Timer
Show users remaining time:
function QuoteTimer ({ expiresAt , onExpire }) {
const [ timeLeft , setTimeLeft ] = useState ( 30 );
useEffect (() => {
const interval = setInterval (() => {
const remaining = Math . max ( 0 , Math . floor (( expiresAt - Date . now ()) / 1000 ));
setTimeLeft ( remaining );
if ( remaining === 0 ) {
onExpire ();
}
}, 1000 );
return () => clearInterval ( interval );
}, [ expiresAt ]);
return < div > Quote expires in: { timeLeft } s </ div > ;
}
Simulation Mode
Test quotes without creating ramps:
POST /api/v2/quotations/simulation
Same parameters as regular quotation, but:
No quotation ID returned
Rate is indicative only
Cannot be used to create ramp
No expiration
Use for:
Showing estimated rates
Calculator functionality
Market rate display
User education
// Get simulated quote for display
const simulatedQuote = await fetch ( '/api/v2/quotations/simulation' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ token } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
fromCurrency: 'COP' ,
toCurrency: 'USDC' ,
amount: userAmount ,
amountIsToCurrency: false ,
cashInMethod: 'PSE' ,
cashOutMethod: 'POLYGON'
})
}). then ( r => r . json ());
// Show rate to user
console . log ( `Estimated rate: ${ simulatedQuote . rate } ` );
console . log ( `You would receive: ${ simulatedQuote . toAmount } USDC` );
// When user confirms, get real quotation
const realQuote = await getQuotation ( /* same params */ );
Quote Updates
Quotations cannot be updated. If you need a different amount or rate, create a new quotation.
// Don't do this - quotations can't be updated
// await updateQuotation(quoteId, newAmount); ❌
// Do this - create new quotation
const newQuote = await getQuotation ( newAmount ); // ✅
Getting Quote By ID
Retrieve a quotation after creation:
GET /api/v2/quotations/{quotationId}
Use Cases:
Verify quote details before ramp
Check if quotation is still valid
Audit/logging purposes
Rate Display Best Practices
Display :
- Source amount : "100,000 COP"
- Destination amount : "23.81 USDC"
- Exchange rate : "1 USDC = 4,200.50 COP"
- Fee information : "Includes 0.5% fee"
"This rate expires in 28 seconds"
- Show visual countdown
- Warn at 10 seconds remaining
- Auto - refresh on expiration
// Auto-refresh quotes periodically
setInterval ( async () => {
const newQuote = await getQuotation ( amount );
updateDisplay ( newQuote );
}, 5000 ); // Every 5 seconds
Show :
- "Rate: 1 USDC = 4,200.50 COP"
- "Market rate: 4,180.25 COP"
- "Spread: 0.48%"
- "Last updated: 2 seconds ago"
Error Handling
Common quotation errors:
Error Cause Solution PAIR_NOT_SUPPORTEDCurrency pair unavailable Check supported pairs AMOUNT_TOO_SMALLBelow minimum Increase amount AMOUNT_TOO_LARGEExceeds user limit Reduce amount or upgrade KYC METHOD_NOT_AVAILABLEPayment method unavailable Choose different method INSUFFICIENT_LIQUIDITYNot enough liquidity Try smaller amount or different method
Rate Comparison
Compare rates across networks:
const compareRates = async ( amount ) => {
const networks = [ 'POLYGON' , 'SOLANA' , 'TRON' , 'ERC20' ];
const quotes = await Promise . all (
networks . map ( network =>
getQuotation ( amount , 'COP' , 'USDC' , 'PSE' , network )
)
);
// Find best rate
const best = quotes . reduce (( prev , curr ) =>
curr . toAmount > prev . toAmount ? curr : prev
);
console . log ( `Best rate: ${ best . rate } on ${ best . cashOutMethod } ` );
return best ;
};
Next Steps