Cotizaciones
La tasa que lees con GET /v2/rate es la que está publicada en ese momento. Entre que la lees, se la muestras a tu usuario y él confirma, pueden pasar varios minutos — y en ese rato la tasa puede moverse. POST /v2/quotes congela un precio: te devuelve los dos montos ya calculados, en enteros, con una vigencia escrita y un solo uso. Mientras la cotización viva, el riesgo de que el mercado se mueva es nuestro, no tuyo.
POST /v2/quotes — congelar el precio
Fijas un lado de la operación y nosotros calculamos el otro. El lado que fijas vuelve exactamente igual: no lo tocamos nunca.
Qué lado fijas: amountType
SOURCE — fijas lo que se debita de tu saldo, en tu moneda. Úsalo cuando tu usuario dice «quiero mandar 50 dólares».
TARGET — fijas lo que le llega al beneficiario, en bolívares. Úsalo cuando tu usuario dice «quiero que le lleguen 2.000 bolívares».
Autenticación e idempotencia
Va firmado, igual que POST /v2/payments, y la cabecera idempotency-key es obligatoria y forma parte del envelope firmado. Repetir la misma clave te devuelve la misma cotización con un 200, no una nueva con un 201. Eso es deliberado: si cada reintento congelara un precio nuevo, una red inestable te dejaría con cinco precios congelados de una sola intención.
# Quiero mandar USD 50,00 — fijo el lado de origen
curl -X POST https://api.alibanca.com/v2/quotes \
-H "x-api-key: sk_test_..." \
-H "x-nonce: $NONCE" \
-H "idempotency-key: cot-2026-09-14-0001" \
-H "x-signature: $FIRMA" \
-H "content-type: application/json" \
-d '{"amountType":"SOURCE","amountMinor":"5000"}'{
"status": "ok",
"traceId": "01J9…",
"payload": {
"quoteId": "9134",
"amountType": "SOURCE",
"sourceCurrency": "USD",
"sourceAmountMinor": "5000",
"targetCurrency": "VES",
"targetAmountMinor": "175002500",
"rateId": "184",
"expiresAt": "2026-09-14T18:47:03.000Z"
}
}Los dos montos vienen calculados. No los recalcules.
La respuesta no trae una tasa para que multipliques: trae los dos montos, en unidades menores enteras. Es la diferencia entre que el redondeo lo decidamos una vez, nosotros, y quede escrito, o que cada integración lo aplique como se le ocurra y termine discrepando con nuestro asiento por un céntimo.
Si multiplicas sourceAmountMinor por el rate de GET /v2/rate puede que no te dé exactamente targetAmountMinor. Eso es correcto. El número bueno es el que está en la cotización.
Hacia dónde redondea
El lado que tú fijas nunca se redondea — vuelve tal cual. El lado calculado se redondea a favor de la casa, y eso quiere decir cosas distintas según el lado:
· Con SOURCE, el monto destino se redondea hacia abajo.
· Con TARGET, el monto de origen se redondea hacia arriba.
En la práctica hablamos de una unidad menor —un céntimo— por operación. Lo decimos explícito porque preferimos que lo sepas al integrar y no que lo descubras cuadrando.
TARGET y montos minúsculos. Si pides que lleguen 0,01 bolívares, el redondeo hacia arriba del lado de origen convierte eso en un céntimo de dólar — miles de veces más de lo que vale. Por eso hay un mínimo del lado destino y por debajo de él la cotización se rechaza con 400. No es un límite comercial: es la aritmética, que a esa escala deja de tener sentido.Vence, y se usa una sola vez
expiresAt está en la respuesta, siempre. No tienes que adivinar cuánto dura ni asumir un número: está escrito. Después de esa hora la cotización está muerta y el pago que la cite se rechaza.
Una cotización respalda un solo pago. Si dos operaciones citan la misma, la segunda se rechaza. No es una validación que podamos olvidarnos de correr: lo impone la base de datos.
Si tu usuario se arrepiente y vuelve a empezar, pide otra cotización con otra idempotency-key. No hay penalidad por pedir cotizaciones que no ejecutas — sólo ocupan cupo hasta que vencen (ver abajo).
Cuándo NO te damos una cotización
Igual que la tasa, esto falla cerrado: si no podemos darte un precio bueno, no te damos ninguno. Cada caso tiene su código porque lo que tienes que hacer en cada uno es distinto.
400 — el pedido no se puede cotizar
Falta amountType, o no es SOURCE ni TARGET; o amountMinor no es un entero positivo de unidades menores escrito como texto; o el monto destino queda por debajo del mínimo. Es tuyo y se arregla mandando otra cosa. El mensaje dice cuál de los tres fue.
404 — no hay conversión que cotizar
Tu saldo ya está en la moneda de pago: fondeas en bolívares y pagas en bolívares. No hay nada que convertir, y devolverte una cotización 1:1 sería inventar una conversión que no existe. Es estructural: reintentar no ayuda. Emite el pago directo, sin cotización.
409 — no hay cupo ahora mismo
Hay un techo a cuánto precio congelado puede haber vivo a la vez, por cliente y en total. Mientras tus cotizaciones están vivas y sin usar, ocupan ese cupo. Tu pedido está bien; lo que falta es espacio. Se resuelve esperando: en cuanto tus cotizaciones venzan o las ejecutes, el cupo se libera solo. No hace falta que hagas nada para liberarlo.
Si te pasa seguido, es señal de que estás pidiendo más cotizaciones de las que ejecutas — o de que tu techo se te quedó chico. Escríbenos y lo miramos.
503 — no hay tasa vigente
Existe el par, pero nadie tiene una tasa publicada y en vigencia en este momento. Es nuestro, no tuyo. Reintenta en un rato. Nunca te vamos a dar una tasa vencida para no dejarte sin respuesta.
GET /v2/rate para mostrar el precio mientras tu usuario decide; pide POST /v2/quotes cuando confirma; emite el pago citando la cotización. Si entre el paso 2 y el 3 pasan más minutos de los que dura expiresAt, pide otra — es barato y es honesto con tu usuario, que va a ver el precio que de verdad se le va a aplicar.