Skip to main content

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

1

Request Quote

Specify currencies, amount, and payment methods
2

Receive Rate

Get locked-in rate valid for 30 seconds
3

Show to User

Display exact amounts user will send/receive
4

Create Ramp

Use quotation ID to execute transaction at quoted rate

Creating a Quotation

POST /api/v2/quotations
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 fiat

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:
  1. Market Rate - Current market price
  2. Payment Method - Different methods have different costs
  3. Volume - Larger transactions may get better rates
  4. Network - Blockchain network affects fees
  5. 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:
ErrorCauseSolution
PAIR_NOT_SUPPORTEDCurrency pair unavailableCheck supported pairs
AMOUNT_TOO_SMALLBelow minimumIncrease amount
AMOUNT_TOO_LARGEExceeds user limitReduce amount or upgrade KYC
METHOD_NOT_AVAILABLEPayment method unavailableChoose different method
INSUFFICIENT_LIQUIDITYNot enough liquidityTry 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