Cotizaciones
Una Quote fija la tasa de cambio y las comisiones de una
transferencia antes de que te comprometas a ella. QuotationsClient envuelve los dos
endpoints que crean y leen cotizaciones. Cada orden referencia exactamente una
cotización, y una cotización respalda exactamente una orden, para siempre — consulta el
resumen del SDK para el recorrido completo de cotización a orden.
Accede a estos métodos directamente en RetornaClient (client.createQuotation(...))
o a través del sub-cliente (client.quotations().createQuotation(...)) — las dos
formas ejecutan el mismo código.
createQuotation(request)
Cotiza una transferencia para un corredor y un método de pago dados, devolviendo una tasa sobre la que puedes actuar antes de que expire.
Firma
public QuotationDetail createQuotation(CreateQuotationRequest request)
Parámetros
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
request | CreateQuotationRequest | Sí | El pedido de cotización. Ver los componentes abajo. |
Componentes de CreateQuotationRequest:
| Componente | Tipo | Requerido | Descripción |
|---|---|---|---|
source | QuotationSource | Sí | Lado de fondeo. Lleva una única currency (String) — la moneda desde la que fondeas. |
destination | QuotationDestination | Sí | country (String, ISO 3166-1 alpha-2 de 2 caracteres, en mayúsculas), currency (String, moneda de destino), payoutMethod (QuotationPayoutMethod, requerido). |
destination.payoutMethod.type | PayoutMethodType | Sí | Uno de los tipos de método de pago soportados por la plataforma. Anidado un nivel dentro de destination.payoutMethod. |
quote | QuotationQuote | Sí | mode (QuoteMode: SEND_EXACT fija el monto de origen, RECEIVE_EXACT fija el monto de destino) y amount (String, decimal con hasta 6 decimales, según ^\d+(\.\d{1,6})?$). |
Retorno
QuotationDetail:
| Accesor | Tipo | Significado |
|---|---|---|
id() | String | Id de la cotización. Pásalo en CreateOrderRequest.quotationId para usarla. |
source() | QuotationSourceDetail | Lado de origen: currency(), decimals() (int), grossAmount() (String, antes de comisiones), netAmount() (String, después de comisiones). |
destination() | QuotationDestinationDetail | El corredor que fijó la cotización: country() (String, ISO-2) y payoutMethod().type() (PayoutMethodType). Las instrucciones de pago de la orden tienen que coincidir con el tipo de payout, o createOrder falla con B2B_QUOTATION_MISMATCH. Los dos son null solo cuando la red no pudo asociar una tasa — no crees una orden sobre esa cotización. |
target() | QuotationTargetDetail | Lado de destino: currency(), decimals() (int), amount() (String, lo que recibe el beneficiario). |
exchangeRate() | ExchangeRate | value() (String), quotedAt() (OffsetDateTime), expiresAt() (OffsetDateTime). Revisa expiresAt() antes de usar la cotización. |
fees() | QuotationFees | totalInSourceCurrency() (String) y breakdown() (List<FeeBreakdownItem>). Cada item tiene description(), pricingType() (PERCENTAGE o FIXED), appliedTo() (etapa a la que se aplica la comisión), value(), y currency(). |
El JSON en el wire es snake_case (gross_amount, exchange_rate,
total_in_source_currency, ...); los accesores de Java de arriba son camelCase —
Jackson mapea entre las dos formas por ti.
Ejemplo
import app.retorna.sdk.RetornaClient;
import app.retorna.sdk.RetornaClientBuilder;
import app.retorna.sdk.core.environment.RetornaEnvironment;
import app.retorna.sdk.models.quotation.CreateQuotationRequest;
import app.retorna.sdk.models.quotation.PayoutMethodType;
import app.retorna.sdk.models.quotation.QuotationDestination;
import app.retorna.sdk.models.quotation.QuotationDetail;
import app.retorna.sdk.models.quotation.QuotationPayoutMethod;
import app.retorna.sdk.models.quotation.QuotationQuote;
import app.retorna.sdk.models.quotation.QuotationSource;
import app.retorna.sdk.models.quotation.QuoteMode;
RetornaClient client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(System.getenv("RETORNA_CLIENT_ID"))
.clientSecret(System.getenv("RETORNA_CLIENT_SECRET"))
.privateKey(System.getenv("RETORNA_PRIVATE_KEY"))
.buildClient();
QuotationDetail quote = client.createQuotation(new CreateQuotationRequest(
new QuotationSource("USDR"),
new QuotationDestination("VE", "VES",
new QuotationPayoutMethod(PayoutMethodType.BANK_TRANSFER)),
new QuotationQuote(QuoteMode.SEND_EXACT, "10.00")));
System.out.printf("id=%s rate=%s expiresAt=%s%n",
quote.id(), quote.exchangeRate().value(), quote.exchangeRate().expiresAt());
System.out.printf("payout=%s → construye la orden con las instrucciones que coincidan%n",
quote.destination().payoutMethod().type()); // P2P_PHONE_TRANSFER → BankPhoneAccount
System.out.printf("receiver gets %s %s (fees: %s %s)%n",
quote.target().amount(), quote.target().currency(),
quote.fees().totalInSourceCurrency(), quote.source().currency());
Errores
IllegalArgumentException— se lanza de forma sincrónica, antes de que salga cualquier request, cuando falta o está mal formado un campo requerido (source.currencyvacío, undestination.countryque no son 2 letras mayúsculas, unquote.modefaltante, o unquote.amountque no cumple el patrón decimal).RetornaB2BExceptionconcodeEnum()uno de:B2B_RATE_NOT_FOUND— no hay tasa activa para el corredor pedido;B2B_UNAUTHORIZED— token o firma rechazados;B2B_RATE_LIMITED— reintentable, con backoff;B2B_PROVIDER_REJECTEDoB2B_PROVIDER_UNAVAILABLE— este último reintentable;B2B_UNKNOWN— reintenta como mucho una vez. Llama ae.codeEnum().isRetryable()en lugar de fijar a mano qué códigos reintentar.RetornaAuthException— falló el propio intercambio de token OAuth2.RetornaSdkException— falla de red o una respuesta que no se pudo deserializar.
Notas
- Una cotización es de un solo uso y con vencimiento: revisa
exchangeRate().expiresAt()antes de crear la orden, y vuelve a cotizar si ya pasó. quote.amounttiene que ser un string decimal. Pasar undoubleo perder precisión al construirlo es la forma más común de terminar con un422confuso.
Referencia de API
getQuotation(id)
Lee una cotización creada previamente por su id — útil para revisar de nuevo su vencimiento o sus términos antes de usarla.
Firma
public QuotationDetail getQuotation(String id)
Parámetros
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
id | String | Sí | El id de la cotización de una llamada previa a createQuotation(). Se valida solo por longitud (1 a 100 caracteres) — trátalo como un string opaco, no como un UUID. |
Retorno
La misma forma de QuotationDetail devuelta por createQuotation arriba.
Ejemplo
import app.retorna.sdk.RetornaClient;
import app.retorna.sdk.RetornaClientBuilder;
import app.retorna.sdk.core.environment.RetornaEnvironment;
import app.retorna.sdk.models.quotation.QuotationDetail;
RetornaClient client = new RetornaClientBuilder()
.environment(RetornaEnvironment.SANDBOX)
.clientId(System.getenv("RETORNA_CLIENT_ID"))
.clientSecret(System.getenv("RETORNA_CLIENT_SECRET"))
.privateKey(System.getenv("RETORNA_PRIVATE_KEY"))
.buildClient();
QuotationDetail quote = client.getQuotation("0190f9b2-0000-7000-8000-000000000000");
System.out.printf("rate=%s expiresAt=%s%n",
quote.exchangeRate().value(), quote.exchangeRate().expiresAt());
Errores
IllegalArgumentException—ides null, vacío, o más largo que 100 caracteres.RetornaB2BExceptionconcodeEnum()uno de:B2B_QUOTATION_NOT_FOUND— no existe o no te pertenece;B2B_UNAUTHORIZED;B2B_RATE_LIMITED— reintentable;B2B_UNKNOWN. Revisae.codeEnum().isRetryable()antes de reintentar.RetornaAuthException— falla del intercambio de token.RetornaSdkException— falla de red o falla de deserialización.
Notas
- El id es opaco. No asumas que es un UUID aunque los ejemplos parezcan uno — el backend no promete ninguna forma más allá de "entre 1 y 100 caracteres."