Koywe

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');

Response:

JSON
{
  "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:

JavaScript
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):

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

Response:

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

BALANCE_TRANSFER Quotes

For currency conversion:

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

Response:

JSON
{
  "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.

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

Supported networks:

NetworkChainCurrencies
ETHEREUMEthereumETH · USDC · USDT
POLYGONPolygonMATIC · USDC · USDT
SOLANASolanaSOL · USDC · USDT
BASEBaseETH · USDC · USDT · EURC
ALGORANDAlgorandUSDC · USDT
TRONTronTRX · USDT
BSCBNB Smart ChainUSDT
BITCOINBitcoinBTC

Only these pairs are valid. Any other symbol/network combination is rejected by the API.

Response:

JSON
{
  "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.

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

Response:

JSON
{
  "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

Drawing diagram…

Example calculation:

Text
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

JavaScript
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:

Text
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:

JavaScript
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

JavaScript
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

JavaScript
// 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

JavaScript
// 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

JavaScript
// 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

JavaScript
// 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