Cotizaciones
Una Cotización fija un tipo de cambio, comisiones y
los montos resultantes antes de que se mueva el dinero. createQuotation
pide una nueva; getQuotation la vuelve a leer. Una cotización es de uso
único — respalda exactamente una orden, para
siempre — y expira, así que la ventana entre cotizar y enviar importa.
createQuotation(...)
Pide una nueva cotización para un corredor origen-destino y fija su tipo de cambio y comisiones.
Firma
createQuotation(req: CreateQuotationRequest): Promise<QuotationDetail>
Parámetros
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
req.source.currency | string | Sí | Siempre "USDR" — los fondos B2B se originan en la wallet USDR. Cualquier otro valor se rechaza del lado del cliente. |
req.destination.country | string | Sí | Código de país destino ISO alpha-2 de 2 caracteres. |
req.destination.currency | string | Sí | Código de moneda destino. |
req.destination.payout_method.type | "BANK_TRANSFER" | "P2P_PHONE_TRANSFER" | Sí | El método de pago con el que se liquidará el monto destino. |
req.quote.mode | "SEND_EXACT" | "RECEIVE_EXACT" | Sí | SEND_EXACT fija el monto origen; RECEIVE_EXACT fija el monto destino. |
req.quote.amount | string | Sí | String decimal, hasta 6 dígitos fraccionarios (^\d+(\.\d{1,6})?$). |
Retorno
QuotationDetail:
| Campo | Tipo | Significado |
|---|---|---|
id | string | Identificador de la cotización. Pásalo como quotation_id a createOrder. |
source.currency | string | Moneda origen — siempre "USDR". |
source.decimals | number | Precisión decimal de los montos origen. |
source.gross_amount | string | Monto origen antes de comisiones. |
source.net_amount | string | Monto origen después de comisiones. |
destination.country | string | null | País de destino que fijó la cotización (ISO-2). |
destination.payout_method.type | string | null | Método de payout que fijó la cotización. Las payment_instructions de la orden tienen que coincidir, o createOrder falla con B2B_QUOTATION_MISMATCH. Los dos campos de destination son null solo cuando la red no pudo asociar una tasa — no crees una orden sobre esa cotización. |
target.currency | string | Moneda destino. |
target.decimals | number | Precisión decimal del monto destino. |
target.amount | string | Monto que recibe el beneficiario. |
exchange_rate.value | string | El tipo de cambio fijado, como string decimal. |
exchange_rate.quoted_at | string | Timestamp ISO 8601 de cuándo se cotizó el tipo de cambio. |
exchange_rate.expires_at | string | Timestamp ISO 8601 en que la cotización deja de ser usable. |
fees.total_in_source_currency | string | Total de comisiones, expresado en la moneda origen. |
fees.breakdown[].description | string | Línea legible por humanos. |
fees.breakdown[].pricing_type | "FEE" | "DISCOUNT" | Si la línea suma o resta al costo. |
fees.breakdown[].applied_to | string | Base sobre la que se calculó la línea, ej. "GROSS" o "NET". |
fees.breakdown[].value | string | Monto de la línea, como string decimal. |
fees.breakdown[].currency | string | Moneda del monto de la línea. |
Ejemplo
import {
RetornaClientBuilder,
RetornaEnvironment,
} from "@retorna-tech/retorna-gateway-sdk";
const client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(process.env.RETORNA_CLIENT_ID!)
.clientSecret(process.env.RETORNA_CLIENT_SECRET!)
.privateKey(process.env.RETORNA_PRIVATE_KEY!)
.buildClient();
const quotation = await client.createQuotation({
source: { currency: "USDR" },
destination: {
country: "VE",
currency: "VES",
payout_method: { type: "BANK_TRANSFER" },
},
quote: { mode: "SEND_EXACT", amount: "10.00" },
});
console.log(quotation.id, quotation.target.amount, quotation.exchange_rate.expires_at);
console.log(quotation.destination.payout_method.type); // "P2P_PHONE_TRANSFER" → usa bank_phone_account en la orden
Errores
Del lado del cliente, antes de cualquier llamada de red (RetornaSdkError):
source.currencyodestination.currencyvacíos, odestination.countryque no tiene exactamente 2 caracteres.destination.payout_method.typefuera deBANK_TRANSFER/P2P_PHONE_TRANSFER.quote.modedistinto deSEND_EXACT/RECEIVE_EXACT, oquote.amountque no cumple el formato de string decimal.
Desde la API (RetornaB2BError, consulta el
catálogo de errores):
B2B_UNAUTHORIZED— credenciales, token o firma rechazados.B2B_RATE_NOT_FOUND— no hay un tipo de cambio activo para el corredor pedido.B2B_RATE_LIMITED— demasiadas requests; reintenta con backoff.B2B_PROVIDER_UNAVAILABLE— la red de pagos no está disponible; reintenta con backoff.B2B_UNKNOWN— falla sin clasificar; reintenta una vez y después escala con elcorrelationId.
Notas
source.currencysolo acepta"USDR"— los fondos siempre se originan en la wallet USDR, lo único que varía es el corredor destino.- La cotización solo es válida hasta
exchange_rate.expires_at. UncreateOrdercontra una cotización expirada falla conB2B_QUOTATION_EXPIRED(consulta órdenes) — pide una cotización nueva en vez de reintentar. - Una cotización es de uso único: una vez que una orden la referencia, un
segundo
createOrdercon el mismoquotation_idfalla conB2B_QUOTATION_ALREADY_USED. Consulta idempotencia.
Referencia de API
getQuotation(id)
Vuelve a leer una cotización previamente creada por id.
Firma
getQuotation(id: string): Promise<QuotationDetail>
Parámetros
| Nombre | Tipo | Obligatorio | Descripción |
|---|---|---|---|
id | string | Sí | El id de cotización devuelto por createQuotation. Entre 1 y 100 caracteres. |
Retorno
QuotationDetail — misma forma que createQuotation más arriba.
Ejemplo
const quotation = await client.getQuotation("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
console.log(quotation.exchange_rate.expires_at);
Errores
Del lado del cliente (RetornaSdkError):
idvacío o más largo que 100 caracteres.
Desde la API (RetornaB2BError):
B2B_UNAUTHORIZED— credenciales, token o firma rechazados.B2B_QUOTATION_NOT_FOUND— la cotización no existe, o no le pertenece a tu compañía.
Notas
- Es de solo lectura: no refresca el tipo de cambio ni extiende
expires_at. - Útil para revisar
exchange_rate.expires_atjusto antes de llamar acreateOrder, porque una cotización que leíste antes puede haber expirado desde entonces.