Conceptos Clave

Cotizaciones y Tasas de Cambio

Comprender cotizaciones y bloqueo de tasas

Cotizaciones y Tasas de Cambio

Las Cotizaciones proporcionan información de tasas de cambio y te permiten bloquear tasas por un período específico antes de crear órdenes.

¿Qué son las Cotizaciones?

Una Cotización es una solicitud de información de tasa de cambio que devuelve:

  • Tasa de cambio actual entre monedas
  • Comisiones (comisión Koywe, comisión de red, comisión de socio)
  • Tiempo de expiración (cuánto tiempo es válida la tasa)
  • Montos esperados (entrada y salida)

Tiempo de Vida (TTL) de Cotización

Validez Corta: Las cotizaciones son válidas por 10-15 segundos solamente. Después de la expiración, debes solicitar una nueva cotización. Siempre verifica el campo expiresAt o validFor.

¿Por qué tan corto?

  • Los mercados de cripto y forex son volátiles
  • Asegura precios precisos y en tiempo real
  • Protege contra manipulación de precios
  • Previene uso de tasas obsoletas

Cuándo Usar Cotizaciones

Usa cotizaciones cuando:

  • Necesites mostrar a los clientes el monto exacto que recibirán
  • Conviertas entre monedas (BALANCE_TRANSFER)
  • Compres o vendas cripto (ONRAMP/OFFRAMP)
  • Quieras transparencia en las tasas

Opcional pero Recomendado: Las cotizaciones son opcionales para la mayoría de tipos de orden pero muy recomendadas para transparencia y mejor experiencia de usuario.


Crear una Cotización

Solicitud Básica de Cotización

1async function getQuote(token, orgId, merchantId, quoteData) {
2 const response = await axios.post(
3 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`,
4 {
5 type: quoteData.type, // Tipo de orden
6 originCurrencySymbol: quoteData.from, // Moneda origen
7 destinationCurrencySymbol: quoteData.to, // Moneda destino
8 amountIn: quoteData.amount // Monto a convertir
9 },
10 {
11 headers: {
12 'Authorization': `Bearer ${token}`,
13 'Content-Type': 'application/json'
14 }
15 }
16 );
17
18 return response.data;
19}
20
21// Uso - Obtener cotización para BALANCE_TRANSFER
22const quote = await getQuote(token, orgId, merchantId, {
23 type: 'BALANCE_TRANSFER',
24 from: 'COP',
25 to: 'USD',
26 amount: 1000000 // 1,000,000 COP
27});
28
29console.log('Tasa de cambio:', quote.exchangeRate);
30console.log('Recibirás:', quote.amountOut, 'USD');
31console.log('Válido por:', quote.validFor, 'segundos');

Respuesta:

1{
2 "id": "qte_abc123xyz",
3 "type": "BALANCE_TRANSFER",
4 "originCurrencySymbol": "COP",
5 "destinationCurrencySymbol": "USD",
6 "amountIn": 1000000,
7 "amountOut": 250,
8 "exchangeRate": 4000,
9 "koyweFee": 5000,
10 "networkFee": 0,
11 "partnerFee": 0,
12 "validFor": 300,
13 "validUntil": 1731513600,
14 "createdAt": "2025-11-13T15:00:00Z"
15}

Campos de Respuesta de Cotización

CampoTipoDescripción
idstringIdentificador único de cotización (usar en órdenes)
typestringTipo de orden (PAYIN, BALANCE_TRANSFER, etc.)
originCurrencySymbolstringMoneda origen
destinationCurrencySymbolstringMoneda destino
amountInnumberMonto de entrada
amountOutnumberMonto de salida (lo que recibirás)
exchangeRatenumberTasa de cambio aplicada
koyweFeenumberComisión de Koywe (en moneda origen)
networkFeenumberComisión de red para cripto (en moneda origen)
partnerFeenumberComisión de socio si aplica
validFornumberSegundos hasta la expiración
validUntilnumberTimestamp Unix de expiración

Usar Cotizaciones en Órdenes

Bloqueo de Tasa

Cuando creas una orden con un quoteId, la tasa de cambio se bloquea:

Node.js
1async function createOrderWithQuote(token, orgId, merchantId) {
2 // 1. Obtener cotización
3 const quote = await axios.post(
4 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`,
5 {
6 type: 'BALANCE_TRANSFER',
7 originCurrencySymbol: 'COP',
8 destinationCurrencySymbol: 'USD',
9 amountIn: 1000000
10 },
11 { headers: { 'Authorization': `Bearer ${token}` } }
12 );
13
14 console.log('Tasa bloqueada en:', quote.data.exchangeRate);
15 console.log('Válido por:', quote.data.validFor, 'segundos');
16
17 // 2. Crear orden con cotización (debe ser dentro del período validFor)
18 const order = await axios.post(
19 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`,
20 {
21 type: 'BALANCE_TRANSFER',
22 originCurrencySymbol: 'COP',
23 destinationCurrencySymbol: 'USD',
24 amountIn: 1000000,
25 quoteId: quote.data.id // Bloquear la tasa de la cotización
26 },
27 { headers: { 'Authorization': `Bearer ${token}` } }
28 );
29
30 console.log('Orden creada con tasa bloqueada');
31 return order.data;
32}

Expiración de Cotización: Las cotizaciones son válidas por un tiempo limitado (típicamente 5 minutos). Si la cotización expira antes de crear la orden, necesitarás obtener una nueva cotización.


Tipos de Cotización por Tipo de Orden

Cotizaciones PAYIN

Para aceptar pagos (típicamente misma moneda, por lo que tasa = 1):

1{
2 "type": "PAYIN",
3 "originCurrencySymbol": "COP",
4 "destinationCurrencySymbol": "COP",
5 "amountIn": 50000
6}

Respuesta:

1{
2 "exchangeRate": 1,
3 "amountOut": 50000,
4 "koyweFee": 500,
5 "networkFee": 0
6}

Cotizaciones BALANCE_TRANSFER

Para conversión de moneda:

1{
2 "type": "BALANCE_TRANSFER",
3 "originCurrencySymbol": "COP",
4 "destinationCurrencySymbol": "USD",
5 "amountIn": 1000000
6}

Respuesta:

1{
2 "exchangeRate": 4000, // 4,000 COP = 1 USD
3 "amountOut": 250, // Recibirás 250 USD
4 "koyweFee": 5000 // 5,000 COP de comisión
5}

Cotizaciones ONRAMP

Para comprar cripto:

Red Requerida: Las cotizaciones ONRAMP requieren un parámetro network para especificar la red blockchain del activo cripto.

1{
2 "type": "ONRAMP",
3 "originCurrencySymbol": "COP",
4 "destinationCurrencySymbol": "USDC",
5 "amountIn": 50000,
6 "network": "ETHEREUM" // Requerido: red blockchain
7}

Redes soportadas:

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

Respuesta:

1{
2 "exchangeRate": 4050, // Incluye precio de cripto
3 "amountOut": 12.34, // Recibirás 12.34 USDC
4 "koyweFee": 500,
5 "networkFee": 2000, // Comisión de red blockchain
6 "network": "ETHEREUM"
7}

Cotizaciones OFFRAMP

Para vender cripto:

Red Requerida: Las cotizaciones OFFRAMP requieren un parámetro network para especificar la red blockchain del activo cripto.

1{
2 "type": "OFFRAMP",
3 "originCurrencySymbol": "USDC",
4 "destinationCurrencySymbol": "COP",
5 "amountIn": 10, // 10 USDC
6 "network": "ETHEREUM" // Requerido: red blockchain
7}

Respuesta:

1{
2 "exchangeRate": 3950, // Ligeramente menor que tasa de compra (spread)
3 "amountOut": 39500, // Recibirás 39,500 COP
4 "koyweFee": 500,
5 "network": "ETHEREUM"
6}

Comprender las Comisiones

Desglose de Comisiones

Cálculo ejemplo:

Monto Entrada: 1,000,000 COP
- Comisión Koywe: -5,000 COP
- Comisión Red: 0 COP
- Comisión Socio: 0 COP
= Monto Neto: 995,000 COP
÷ Tasa Cambio: ÷4,000 COP/USD
= Monto Salida: 248.75 USD

Tipos de Comisiones

Tipo de ComisiónCuándo se AplicaRango Típico
Comisión KoyweTodas las transacciones0.5% - 2%
Comisión RedTransacciones cripto (ONRAMP/OFFRAMP)Variable (comisiones blockchain)
Comisión SocioSi usas integraciones de sociosVaría por socio

Mostrar Tasas a Usuarios

Visualización Amigable

Node.js
1async function displayQuoteToUser(token, orgId, merchantId, amount) {
2 const quote = await getQuote(token, orgId, merchantId, {
3 type: 'BALANCE_TRANSFER',
4 from: 'COP',
5 to: 'USD',
6 amount: amount
7 });
8
9 // Formatear para mostrar al usuario
10 const display = {
11 amountToSend: `${amount.toLocaleString()} COP`,
12 willReceive: `${quote.amountOut.toFixed(2)} USD`,
13 exchangeRate: `1 USD = ${quote.exchangeRate.toLocaleString()} COP`,
14 totalFees: `${quote.koyweFee.toLocaleString()} COP`,
15 expiresIn: `${Math.floor(quote.validFor / 60)} minutos`,
16 effectiveRate: (amount / quote.amountOut).toFixed(2) + ' COP/USD'
17 };
18
19 console.log('Envías:', display.amountToSend);
20 console.log('Recibes:', display.willReceive);
21 console.log('Tasa de cambio:', display.exchangeRate);
22 console.log('Comisiones totales:', display.totalFees);
23 console.log('Tasa expira en:', display.expiresIn);
24 console.log('Tasa efectiva:', display.effectiveRate);
25
26 return quote;
27}
28
29// Uso
30await displayQuoteToUser(token, orgId, merchantId, 1000000);

Salida:

Envías: 1,000,000 COP
Recibes: 248.75 USD
Tasa de cambio: 1 USD = 4,000 COP
Comisiones totales: 5,000 COP
Tasa expira en: 5 minutos
Tasa efectiva: 4020.00 COP/USD

Recuperar una Cotización

Obtener detalles de una cotización existente:

Node.js
1async function getQuoteById(token, orgId, merchantId, quoteId) {
2 const response = await axios.get(
3 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes/${quoteId}`,
4 {
5 headers: { 'Authorization': `Bearer ${token}` }
6 }
7 );
8
9 return response.data;
10}
11
12// Uso
13const quote = await getQuoteById(token, orgId, merchantId, 'qte_abc123');
14console.log('Estado de cotización:', quote);

Mejores Prácticas

Cuándo Obtener una Cotización

Siempre obtén una cotización para:

  • Conversiones de moneda (BALANCE_TRANSFER)
  • Operaciones cripto (ONRAMP/OFFRAMP)
  • Mostrar tasa a usuarios antes de que confirmen

Visualización de Tasa

Muestra a los usuarios:

  • Tasa de cambio en términos familiares (1 USD = X COP)
  • Comisiones totales claramente separadas
  • Tasa efectiva (incluyendo comisiones)
  • Tiempo de expiración

Manejo de Expiración

Node.js
1async function createOrderWithAutoRetry(token, orgId, merchantId, orderData) {
2 let quote = await getQuote(token, orgId, merchantId, {
3 type: orderData.type,
4 from: orderData.from,
5 to: orderData.to,
6 amount: orderData.amount
7 });
8
9 try {
10 // Intentar crear orden con cotización
11 return await createOrderWithQuote(token, orgId, merchantId, quote.id);
12 } catch (error) {
13 if (error.message.includes('expired') || error.message.includes('invalid quote')) {
14 // Cotización expirada, obtener nueva cotización y reintentar
15 console.log('Cotización expirada, obteniendo nueva cotización...');
16 quote = await getQuote(token, orgId, merchantId, {
17 type: orderData.type,
18 from: orderData.from,
19 to: orderData.to,
20 amount: orderData.amount
21 });
22
23 return await createOrderWithQuote(token, orgId, merchantId, quote.id);
24 }
25 throw error;
26 }
27}

Cotización vs Sin Cotización

Con Cotización

1// 1. Obtener cotización
2const quote = await getQuote(...);
3
4// 2. Mostrar tasa al usuario
5console.log('Tasa:', quote.exchangeRate);
6
7// 3. Usuario confirma
8
9// 4. Crear orden con tasa bloqueada
10const order = await createOrder({
11 ...orderData,
12 quoteId: quote.id
13});

Beneficios:

  • Tasa bloqueada
  • Usuario sabe exactamente qué recibirá
  • Mejor transparencia

Sin Cotización

1// Crear orden directamente (usa tasa actual)
2const order = await createOrder({
3 type: 'BALANCE_TRANSFER',
4 originCurrencySymbol: 'COP',
5 destinationCurrencySymbol: 'USD',
6 amountIn: 1000000
7 // Sin quoteId - usa tasa actual
8});

Consideraciones:

  • Tasa determinada al momento de creación de orden
  • Pequeña fluctuación de tasa posible
  • Más rápido (una llamada API menos)

Escenarios Comunes

Escenario 1: Mostrar Tasa Antes de Pago

1// Usuario ve página de checkout
2const quote = await getQuote(token, orgId, merchantId, {
3 type: 'PAYIN',
4 from: 'COP',
5 to: 'COP',
6 amount: 50000
7});
8
9// Mostrar al usuario
10console.log(`Pagar ${quote.amountIn} COP`);
11console.log(`Comisión: ${quote.koyweFee} COP`);
12console.log(`Total: ${quote.amountIn + quote.koyweFee} COP`);
13
14// Usuario hace clic en "Pagar"
15const order = await createOrder({
16 ...orderData,
17 quoteId: quote.id
18});

Escenario 2: Herramienta Conversora de Moneda

1// Convertidor de moneda en tiempo real
2async function convertCurrency(amount, from, to) {
3 const quote = await getQuote(token, orgId, merchantId, {
4 type: 'BALANCE_TRANSFER',
5 from: from,
6 to: to,
7 amount: amount
8 });
9
10 return {
11 from: `${amount} ${from}`,
12 to: `${quote.amountOut} ${to}`,
13 rate: `1 ${to} = ${quote.exchangeRate} ${from}`,
14 fee: `${quote.koyweFee} ${from}`
15 };
16}
17
18// Uso
19const result = await convertCurrency(1000000, 'COP', 'USD');
20console.log(result);
21// { from: "1000000 COP", to: "248.75 USD", rate: "1 USD = 4000 COP", fee: "5000 COP" }

Próximos Pasos