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
| Field | Type | Description |
|---|---|---|
id | string | Unique quote identifier (use in orders) |
orderType | string | Order type (PAYIN, BALANCE_TRANSFER, etc.) |
originCurrencySymbol | string | Source currency |
destinationCurrencySymbol | string | Target currency |
requestedAmountIn | number | Original requested input amount |
requestedAmountOut | number | Original requested output amount |
finalAmountIn | number | Total amount the user pays (origin currency) |
finalAmountOut | number | Total amount the user receives (destination currency) |
exchangeRate | number | Effective exchange rate applied |
fee | number | Total fees charged (base fees + tax on fees, in origin currency) |
taxes | number | Total taxes applied to the transaction amount |
validForSeconds | number | Seconds until expiration |
validUntil | string | ISO timestamp of expiration |
components | array | Detailed breakdown of fees and taxes |
summary | object | Summary 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 USDThe components array in the response provides the detailed breakdown of each fee and tax applied. The summary object provides totals.
Fee Types
| Fee Type | When Applied | Typical Range |
|---|---|---|
| Processing Fee | All transactions | 0.5% - 2% |
| Network Fee | Crypto transactions (ONRAMP/OFFRAMP) | Variable (blockchain fees) |
| Tax on Amount | Country-specific (e.g., VAT) | Varies by country |
| Tax on Fee | Country-specific | Varies 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/USDRetrieving 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" }