Saltar al contenido principal

Devoluciones y vuelto

Contrato

Estas operaciones están en producción, pero todavía no aparecen en la referencia interactiva; se agregarán en una próxima versión del contrato. Esta guía describe su comportamiento actual.

Una venta cobrada se devuelve por el mismo riel y al mismo pagador que la pagó: nunca a un tercero. El vuelto, en cambio, es parte del cobro: se entrega en el momento al cliente que está en caja.

OperaciónRutaAlcance de la clave
Solicitar una devoluciónPOST /api/v1/pagos/intenciones/{ref}/devolucionesINTEGRACION o COMPLETO
Listar las devoluciones de una ventaGET /api/v1/pagos/intenciones/{ref}/devolucionesINTEGRACION o COMPLETO
Consultar una devoluciónGET /api/v1/pagos/devoluciones/{refundCode}INTEGRACION o COMPLETO
Autorizar una devoluciónPOST /api/v1/pagos/devoluciones/{refundCode}/autorizarVer cuatro ojos
Cancelar una devoluciónPOST /api/v1/pagos/devoluciones/{refundCode}/cancelarINTEGRACION o COMPLETO
Entregar el vueltoPOST /api/v1/pagos/intenciones/{ref}/vueltoINTEGRACION, COMPLETO o EQUIPOS con permiso de vuelto
Listar los vueltos de una ventaGET /api/v1/pagos/intenciones/{ref}/vueltoIgual que el anterior
Tasa de cambio vigenteGET /api/v1/pagos/tasa-cambio/vigente?moneda=USDINTEGRACION, COMPLETO o EQUIPOS

Devoluciones​

EN_DUDA nunca se reintenta a ciegas: la conciliación consulta al banco y decide.

1. Solicitar​

curl -s -X POST https://pos.finoracore.com/api/v1/pagos/intenciones/FNRLZ3K9Q1/devoluciones \
-H "X-API-Key: $FINORA_API_KEY" \
-H "Idempotency-Key: dev-ped-8841-01" \
-H "Content-Type: application/json" \
-d '{
"monto": 1500.00,
"moneda": "VES",
"motivo": "PRODUCTO_DEFECTUOSO",
"motivoTexto": "caja golpeada",
"intentoSecuencia": 1,
"solicitadoPor": "caja:ana",
"lineas": [ { "codigo": "SKU-1", "descripcion": "Licuadora", "cantidad": 1, "monto": 1500.00 } ]
}'
CampoObligatorioNotas
montosíMayor que cero y no mayor que lo pagado menos lo ya devuelto.
motivosíCLIENTE_ARREPENTIDO, PRODUCTO_DEFECTUOSO, SERVICIO_NO_PRESTADO, ERROR_CAJERO, COBRO_DUPLICADO, SOSPECHA_FRAUDE u OTRO.
solicitadoPorsíQuién opera en tu sistema (por ejemplo caja:ana). Se usa para el control de cuatro ojos.
intentoSecuencianoQué intento de cobro aprobado se devuelve, si la venta tuvo varios.
rielForzadonoSolo EFECTIVO o NOTA_CREDITO, cuando el pago no tiene salida bancaria al mismo pagador.
lineasnoDetalle de lo devuelto.

Idempotency-Key (recomendada, hasta 64 caracteres): repetirla devuelve la devolución ya creada con 200. Respuesta 202:

{
"refundCode": "DEV-20261020-7F3A2C",
"estado": "SOLICITADA",
"tipo": "DEVOLUCION",
"riel": "P2P",
"monto": 1500.00,
"moneda": "VES",
"motivo": "PRODUCTO_DEFECTUOSO",
"motivoTexto": "caja golpeada",
"intencion": "FNRLZ3K9Q1",
"intentoSecuencia": 1,
"rielOrigen": "PAGO_MOVIL",
"beneficiario": { "tipoDocumento": "V", "documento": "V-****5678", "telefono": "0414***0000", "banco": "0999" },
"solicitadoPor": "caja:ana",
"autorizadoPor": null,
"creadoEn": "2026-10-20T15:02:11Z",
"autorizadoEn": null,
"aplicadoEn": null,
"salida": null,
"notaCredito": null,
"motivoRechazo": null,
"terminalId": "TERM0042",
"merchantCode": "COM00042"
}

El beneficiario se copia del pago original y viene enmascarado; el cuerpo de la petición no puede indicar otro.

Por qué riel sale​

El Merchant elige el riel de salida (riel) a partir del pago original:

Pago originalRiel de salida
Tarjeta en un terminalAnulación si el lote del terminal sigue abierto; si no, devolución por tarjeta.
Pago móvil aprobado hoy con código de reversoReverso del pago móvil.
Pago móvil, transferencia o crédito/débito inmediato de persona natural, hasta el topePago móvil al mismo teléfono y documento (P2P).
Ídem con pagador persona jurídica o por encima del topeCrédito inmediato a la cuenta del pagador.
EfectivoEFECTIVO: registro y nota de crédito; el dinero sale por caja.
Sin pagador identificado422 RIEL_SIN_SALIDA: pide rielForzado EFECTIVO o NOTA_CREDITO.

Cuatro ojos​

Una devolución la autoriza otra persona distinta de quien la solicitó. Al autorizar se ejecuta en la misma llamada y la respuesta trae el estado final (APLICADA, EN_DUDA o FALLIDA) con el bloque salida.

  • Desde el portal del comercio (recomendado): un administrador autoriza hasta el tope de supervisor del comercio; por encima, el propietario.
  • Por clave API: POST /api/v1/pagos/devoluciones/{refundCode}/autorizar con { "autorizadoPor": "supervisor:luis" }. Está desactivada por defecto, porque una clave no distingue personas; si no está habilitada para tu comercio, responde 403 CONTROL_DUAL. Aun habilitada, por clave solo se autoriza hasta el tope de supervisor (403 ROL_INSUFICIENTE por encima).

El tope se compara contra el total acumulado devuelto de la venta, no contra cada solicitud: partir una devolución grande en varias pequeñas no evita la aprobación de mayor nivel.

salida (tras ejecutar)
{
"id": 9, "concepto": "DEVOLUCION", "riel": "P2P", "estado": "APLICADA",
"monto": 1500.00, "moneda": "VES", "montoOriginal": null, "monedaOriginal": null, "tasaCambio": null,
"idExterno": "DEV-20261020-7F3A2C", "referenciaBanco": "000123456789", "codigoAnulacion": null,
"codigoRespuesta": "201", "mensaje": null, "gateway": "SIMULADO",
"beneficiario": { "tipoDocumento": "V", "documento": "V-****5678", "telefono": "0414***0000", "banco": "0999" },
"ejecutadoEn": "2026-10-20T15:05:40Z", "conciliadoEn": null
}

Tras APLICADA, la devolución trae además notaCredito con su número, fecha y monto.

Cancelar​

POST /api/v1/pagos/devoluciones/{refundCode}/cancelar con { "motivo": "…" }. Solo en SOLICITADA o AUTORIZADA; la devolución queda RECHAZADA.

Errores​

HTTPcodigoCuándo
400PETICION_INVALIDAMonto ≤ 0, motivo fuera del catálogo o solicitadoPor vacío.
403CONTROL_DUALAutoriza la misma persona que solicitó, o la autorización por clave está desactivada.
403ROL_INSUFICIENTEEl acumulado supera el tope de quien autoriza.
404INTENCION_NO_ENCONTRADA, DEVOLUCION_NO_ENCONTRADAReferencia inexistente o fuera del alcance de la clave.
409INTENCION_NO_PAGADALa venta no está PAGADA.
409DEVOLUCION_DUPLICADAMisma Idempotency-Key con otro cuerpo.
409ESTADO_INVALIDOLa devolución no admite la operación en su estado.
422MONTO_SUPERA_DISPONIBLEEl monto supera lo pagado menos lo devuelto.
422RIEL_SIN_SALIDANo hay salida al mismo pagador y no se forzó EFECTIVO o NOTA_CREDITO.

Vuelto​

El vuelto sale por pago móvil al cliente que está en caja. No lleva cuatro ojos, pero sí un tope por operación, y la venta debe estar PAGADA.

curl -s -X POST https://pos.finoracore.com/api/v1/pagos/intenciones/FNRLZ3K9Q1/vuelto \
-H "X-API-Key: $FINORA_API_KEY" -H "Content-Type: application/json" \
-d '{
"monto": 2.00, "moneda": "USD",
"telefono": "04140000000", "tipoDocumento": "V", "documento": "12345678", "banco": "0999",
"solicitadoPor": "caja:ana"
}'
  • moneda es opcional (por defecto, la de la venta). Si no es VES, se convierte con la tasa oficial vigente hoy, redondeada a 2 decimales, y la tasa queda congelada en la salida.
  • Sin tasa vigente para hoy: 422 TASA_CAMBIO_NO_DISPONIBLE y no se crea nada. Nunca se usa la tasa de ayer en silencio: ofrece el vuelto en efectivo.
  • El beneficiario debe ser persona natural (V, E o P).
  • Un solo vuelto activo o aplicado por venta (409 VUELTO_YA_EN_CURSO); tras uno FALLIDA se puede reintentar.
  • Por encima del tope del comercio, en bolívares: 422 VUELTO_SUPERA_TOPE.

Respuesta 201 (la salida, con la conversión):

{
"id": 12, "concepto": "VUELTO", "riel": "P2P", "estado": "APLICADA",
"monto": 73.00, "moneda": "VES",
"montoOriginal": 2.00, "monedaOriginal": "USD",
"tasaCambio": { "tasa": 36.50000000, "monedaOrigen": "USD", "monedaDestino": "VES",
"fechaValor": "2026-10-20", "fuente": "BCV", "id": 118 },
"idExterno": "VLT-FNRLZ3K9Q1-1", "referenciaBanco": "000123456790", "codigoAnulacion": null,
"codigoRespuesta": "201", "mensaje": null, "gateway": "SIMULADO",
"beneficiario": { "tipoDocumento": "V", "documento": "V-****5678", "telefono": "0414***0000", "banco": "0999" },
"ejecutadoEn": "2026-10-20T15:10:02Z", "conciliadoEn": null
}

El comprobante del cliente debe mostrar el monto en divisa, la tasa con su fecha valor y el monto en bolívares enviado.

Consultar la tasa antes de pedir el vuelto​

curl -s "https://pos.finoracore.com/api/v1/pagos/tasa-cambio/vigente?moneda=USD" -H "X-API-Key: $FINORA_API_KEY"
{ "tasa": 36.50000000, "monedaOrigen": "USD", "monedaDestino": "VES",
"fechaValor": "2026-10-20", "fuente": "BCV", "id": 118, "vigenteHasta": "2026-10-20" }

Es la misma tasa que congelaría un vuelto en ese instante. Entre la consulta y el vuelto la tasa puede cambiar (por ejemplo, al pasar la medianoche): lo que vale para el comprobante es siempre el tasaCambio que devuelve el vuelto. moneda VES o mal formada responde 400 MONEDA_NO_SOPORTADA.

Avisos por webhook​

Si tu venta vino de una sesión de checkout con webhookUrl, o tu comercio tiene una URL de webhook configurada, recibes devolucion.creada, devolucion.aprobada, devolucion.ejecutada, devolucion.en_duda, devolucion.fallida, devolucion.conciliada y vuelto.ejecutado, firmados como los demás webhooks del Merchant. El cuerpo es la devolución (o la salida del vuelto) más evento y ocurridoEn.