Skip to Content
Core ConceptsQuotes & Exchange Rates

Quotes & Exchange Rates

Quotes provide exchange rate information and allow you to lock rates for a specific time period before creating orders.

What are Quotes?

A Quote is a request for exchange rate information that returns:

  • Current exchange rate between currencies
  • Fees and taxes breakdown
  • Expiration time (how long the rate is valid)
  • Expected amounts (input and output)

Quote Time-to-Live (TTL)

Short Validity: Quotes are valid for 10-15 seconds only. After expiration, you must request a new quote. Always check the validForSeconds or validUntil field.

Why so short?

  • Crypto and forex markets are volatile
  • Ensures accurate, real-time pricing
  • Protects against price manipulation
  • Prevents stale rate usage

When to Use Quotes

Use quotes when:

  • You need to show customers the exact amount they’ll receive
  • Converting between currencies (BALANCE_TRANSFER)
  • Buying or selling crypto (ONRAMP/OFFRAMP)
  • You want rate transparency

Optional but Recommended: Quotes are optional for most order types but highly recommended for transparency and better user experience.


Creating a Quote

Basic Quote Request

async function getQuote(token, orgId, merchantId, quoteData) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`, { orderType: quoteData.orderType, // Order type (PAYIN, PAYOUT, BALANCE_TRANSFER, ONRAMP, OFFRAMP) executable: true, // Whether the quote can be used to create an order originCurrencySymbol: quoteData.from, // Source currency destinationCurrencySymbol: quoteData.to, // Target currency amountIn: quoteData.amount // Amount to convert }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } // Usage - Get quote for BALANCE_TRANSFER const quote = await getQuote(token, orgId, merchantId, { orderType: 'BALANCE_TRANSFER', from: 'COP', to: 'USD', amount: 1000000 // 1,000,000 COP }); console.log('Exchange rate:', quote.exchangeRate); console.log('Will receive:', quote.finalAmountOut, 'USD'); console.log('Valid for:', quote.validForSeconds, 'seconds');
def get_quote(token, org_id, merchant_id, quote_data): response = requests.post( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/quotes', json={ 'orderType': quote_data['order_type'], 'executable': True, 'originCurrencySymbol': quote_data['from'], 'destinationCurrencySymbol': quote_data['to'], 'amountIn': quote_data['amount'] }, headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } ) return response.json() # Usage quote = get_quote(token, org_id, merchant_id, { 'order_type': 'BALANCE_TRANSFER', 'from': 'COP', 'to': 'USD', 'amount': 1000000 }) print(f"Exchange rate: {quote['exchangeRate']}") print(f"Will receive: {quote['finalAmountOut']} USD")
curl -X POST 'https://api-sandbox.koywe.com/api/v1/organizations/YOUR_ORG_ID/merchants/YOUR_MERCHANT_ID/quotes' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "orderType": "BALANCE_TRANSFER", "executable": true, "originCurrencySymbol": "COP", "destinationCurrencySymbol": "USD", "amountIn": 1000000 }'

Response:

{ "id": "qte_abc123xyz", "orderType": "BALANCE_TRANSFER", "originCurrencySymbol": "COP", "destinationCurrencySymbol": "USD", "requestedAmountIn": 1000000, "finalAmountIn": 1000000, "finalAmountOut": 250, "exchangeRate": 4000, "fee": 5000, "taxes": 0, "validForSeconds": 300, "validUntil": "2025-11-13T15:05:00Z", "components": [ { "type": "FEE", "code": "PROCESSING_FEE", "name": "Processing Fee", "currency": "COP", "calculatedAmount": 5000 } ], "summary": { "totalBaseFeesInOriginCurrency": 5000, "totalTaxOnFeeInOriginCurrency": 0, "totalEffectiveFeeInOriginCurrency": 5000, "amountToBeConverted": 995000 } }

Quote Response Fields

FieldTypeDescription
idstringUnique quote identifier (use in orders)
orderTypestringOrder type (PAYIN, BALANCE_TRANSFER, etc.)
originCurrencySymbolstringSource currency
destinationCurrencySymbolstringTarget currency
requestedAmountInnumberOriginal requested input amount
requestedAmountOutnumberOriginal requested output amount
finalAmountInnumberTotal amount the user pays (origin currency)
finalAmountOutnumberTotal amount the user receives (destination currency)
exchangeRatenumberEffective exchange rate applied
feenumberTotal fees charged (base fees + tax on fees, in origin currency)
taxesnumberTotal taxes applied to the transaction amount
validForSecondsnumberSeconds until expiration
validUntilstringISO timestamp of expiration
componentsarrayDetailed breakdown of fees and taxes
summaryobjectSummary of financial calculations

Using Quotes in Orders

Rate Locking

When you create an order with a quoteId, the exchange rate is locked:

async function createOrderWithQuote(token, orgId, merchantId) { // 1. Get quote const quote = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`, { orderType: 'BALANCE_TRANSFER', executable: true, originCurrencySymbol: 'COP', destinationCurrencySymbol: 'USD', amountIn: 1000000 }, { headers: { 'Authorization': `Bearer ${token}` } } ); console.log('Rate locked at:', quote.data.exchangeRate); console.log('Valid for:', quote.data.validForSeconds, 'seconds'); // 2. Create order with quote (must be within validFor period) const order = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'BALANCE_TRANSFER', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'USD', amountIn: 1000000, quoteId: quote.data.id // Lock the rate from quote }, { headers: { 'Authorization': `Bearer ${token}` } } ); console.log('Order created with locked rate'); return order.data; }

Quote Expiration: Quotes are valid for a limited time (10-15 seconds). If the quote expires before you create the order, you’ll need to get a new quote.


Quote Types by Order Type

PAYIN Quotes

For accepting payments (typically same currency, so rate = 1):

{ "orderType": "PAYIN", "executable": true, "originCurrencySymbol": "COP", "destinationCurrencySymbol": "COP", "amountIn": 50000 }

Response:

{ "exchangeRate": 1, "finalAmountIn": 50000, "finalAmountOut": 50000, "fee": 500, "taxes": 0 }

BALANCE_TRANSFER Quotes

For currency conversion:

{ "orderType": "BALANCE_TRANSFER", "executable": true, "originCurrencySymbol": "COP", "destinationCurrencySymbol": "USD", "amountIn": 1000000 }

Response:

{ "exchangeRate": 4000, // 4,000 COP = 1 USD "finalAmountOut": 250, // Will receive 250 USD "fee": 5000, // 5,000 COP total fees "taxes": 0 }

ONRAMP Quotes

For buying crypto:

Network Required: ONRAMP quotes require a network parameter to specify the blockchain network for the crypto asset.

{ "orderType": "ONRAMP", "executable": true, "originCurrencySymbol": "COP", "destinationCurrencySymbol": "USDC", "amountIn": 50000, "network": "ETHEREUM" // Required for ONRAMP/OFFRAMP }

Supported networks:

  • ETHEREUM (for USDC, USDT, ETH)
  • POLYGON (for USDC, USDT, MATIC)
  • BSC (for USDC, USDT, BNB)
  • BITCOIN (for BTC)
  • TRON (for USDT)

Response:

{ "exchangeRate": 4050, // Includes crypto price "finalAmountOut": 12.34, // Will receive 12.34 USDC "fee": 2500, // Total fees (includes network fee) "taxes": 0 }

OFFRAMP Quotes

For selling crypto:

Network Required: OFFRAMP quotes require a network parameter to specify the blockchain network for the crypto asset.

{ "orderType": "OFFRAMP", "executable": true, "originCurrencySymbol": "USDC", "destinationCurrencySymbol": "COP", "amountIn": 10, // 10 USDC "network": "ETHEREUM" // Required for ONRAMP/OFFRAMP }

Response:

{ "exchangeRate": 3950, // Slightly lower than buy rate (spread) "finalAmountOut": 39500, // Will receive 39,500 COP "fee": 500, // Total fees "taxes": 0 }

Understanding Fees

Fee Breakdown

Example calculation:

Amount In (finalAmountIn): 1,000,000 COP - Fee: -5,000 COP - Taxes: 0 COP = Net Amount: 995,000 COP ÷ Exchange Rate: ÷4,000 COP/USD = Amount Out (finalAmountOut): 248.75 USD

The components array in the response provides the detailed breakdown of each fee and tax applied. The summary object provides totals.

Fee Types

Fee TypeWhen AppliedTypical Range
Processing FeeAll transactions0.5% - 2%
Network FeeCrypto transactions (ONRAMP/OFFRAMP)Variable (blockchain fees)
Tax on AmountCountry-specific (e.g., VAT)Varies by country
Tax on FeeCountry-specificVaries by country

Showing Rates to Users

User-Friendly Display

async function displayQuoteToUser(token, orgId, merchantId, amount) { const quote = await getQuote(token, orgId, merchantId, { orderType: 'BALANCE_TRANSFER', from: 'COP', to: 'USD', amount: amount }); // Format for user display const display = { amountToSend: `${amount.toLocaleString()} COP`, willReceive: `${quote.finalAmountOut.toFixed(2)} USD`, exchangeRate: `1 USD = ${quote.exchangeRate.toLocaleString()} COP`, totalFees: `${quote.fee.toLocaleString()} COP`, expiresIn: `${Math.floor(quote.validForSeconds / 60)} minutes`, effectiveRate: (amount / quote.finalAmountOut).toFixed(2) + ' COP/USD' }; console.log('You send:', display.amountToSend); console.log('They receive:', display.willReceive); console.log('Exchange rate:', display.exchangeRate); console.log('Total fees:', display.totalFees); console.log('Rate expires in:', display.expiresIn); console.log('Effective rate:', display.effectiveRate); return quote; } // Usage await displayQuoteToUser(token, orgId, merchantId, 1000000);

Output:

You send: 1,000,000 COP They receive: 248.75 USD Exchange rate: 1 USD = 4,000 COP Total fees: 5,000 COP Rate expires in: 5 minutes Effective rate: 4020.00 COP/USD

Retrieving a Quote

Get details of an existing quote:

async function getQuoteById(token, orgId, merchantId, quoteId) { const response = await axios.get( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes/${quoteId}`, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } // Usage const quote = await getQuoteById(token, orgId, merchantId, 'qte_abc123'); console.log('Quote status:', quote);

Best Practices

When to Get a Quote

Always get a quote for:

  • Currency conversions (BALANCE_TRANSFER)
  • Crypto operations (ONRAMP/OFFRAMP)
  • Showing rate to users before they commit

Rate Display

Show users:

  • Exchange rate in familiar terms (1 USD = X COP)
  • Total fees clearly separated
  • Effective rate (including fees)
  • Expiration time

Handling Expiration

async function createOrderWithAutoRetry(token, orgId, merchantId, orderData) { let quote = await getQuote(token, orgId, merchantId, { orderType: orderData.orderType, from: orderData.from, to: orderData.to, amount: orderData.amount }); try { // Try to create order with quote return await createOrderWithQuote(token, orgId, merchantId, quote.id); } catch (error) { if (error.message.includes('expired') || error.message.includes('invalid quote')) { // Quote expired, get new quote and retry console.log('Quote expired, getting new quote...'); quote = await getQuote(token, orgId, merchantId, { orderType: orderData.orderType, from: orderData.from, to: orderData.to, amount: orderData.amount }); return await createOrderWithQuote(token, orgId, merchantId, quote.id); } throw error; } }

Quote vs No Quote

With Quote

// 1. Get quote const quote = await getQuote(...); // 2. Show user the rate console.log('Rate:', quote.exchangeRate); // 3. User confirms // 4. Create order with locked rate const order = await createOrder({ ...orderData, quoteId: quote.id });

Benefits:

  • Rate locked
  • User knows exactly what they’ll receive
  • Better transparency

Without Quote

// Create order directly (uses current rate) const order = await createOrder({ type: 'BALANCE_TRANSFER', originCurrencySymbol: 'COP', destinationCurrencySymbol: 'USD', amountIn: 1000000 // No quoteId - uses current rate });

Considerations:

  • Rate determined at order creation time
  • Small rate fluctuation possible
  • Faster (one less API call)

Common Scenarios

Scenario 1: Show Rate Before Payment

// User views checkout page const quote = await getQuote(token, orgId, merchantId, { orderType: 'PAYIN', from: 'COP', to: 'COP', amount: 50000 }); // Display to user console.log(`Pay ${quote.finalAmountIn} COP`); console.log(`Fee: ${quote.fee} COP`); console.log(`Total: ${quote.finalAmountIn} COP`); // finalAmountIn already includes fees // User clicks "Pay" const order = await createOrder({ ...orderData, quoteId: quote.id });

Scenario 2: Currency Converter Tool

// Real-time currency converter async function convertCurrency(amount, from, to) { const quote = await getQuote(token, orgId, merchantId, { orderType: 'BALANCE_TRANSFER', from: from, to: to, amount: amount }); return { from: `${amount} ${from}`, to: `${quote.finalAmountOut} ${to}`, rate: `1 ${to} = ${quote.exchangeRate} ${from}`, fee: `${quote.fee} ${from}` }; } // Usage const result = await convertCurrency(1000000, 'COP', 'USD'); console.log(result); // { from: "1000000 COP", to: "248.75 USD", rate: "1 USD = 4000 COP", fee: "5000 COP" }

Next Steps

Last updated on