Anulación, reembolso y recibos
Estas operaciones actúan sobre una transacción, identificada por el UUID transaction_id de la
respuesta del pago, nunca por el id numérico del pago.
Esa distinción importa porque un enlace reutilizable puede llevar varias transacciones: anular o reembolsar la transacción de un cliente deja las demás intactas.
| Operación | Ruta |
|---|---|
| Anulación | POST /payments/{transaction_id}/void |
| Reembolso | POST /payments/{transaction_id}/refund |
| Metadatos del recibo | GET /payments/{transaction_id}/receipt |
| PDF del recibo | GET /payments/{transaction_id}/receipt/download |
13.1 Pasar el identificador equivocado parece un endpoint inexistente
La ruta solo coincide con el formato UUID, así que un id numérico de pago produce un 404 de ruteo:
POST /payments/9e2b6a34-6f1d-4e2a-8c9b-2f7a1d4e5c6b/void -> the route matched
POST /payments/873/void -> "The route ... could not be found."
Si ves ese mensaje en una anulación, un reembolso o un recibo, pasaste el id del pago donde va el UUID de la transacción. El endpoint está ahí.
13.2 ¿Anulación o reembolso?
| Anulación | Reembolso | |
|---|---|---|
| Cuándo | El mismo día, antes de la liquidación | Después de la liquidación |
| Monto | Solo total | Total o parcial |
| Velocidad | Inmediata | 3-5 días hábiles de vuelta a la tarjeta |
| El cliente ve | Que en realidad nunca se le cobró | Dinero devuelto |
| Webhook | payment.voided |
payment.refunded / payment.partially_refunded |
| Caso típico | Error, cancelación inmediata | Devolución, disputa, cobro de más |
La elegibilidad la gobierna la ventana de tiempo configurada de la transacción, no solo el estado de
liquidación. Intentar un reembolso demasiado pronto puede devolver 422 con un mensaje del
procesador como "Invalid transaction" - ese texto viene del procesador y no es una respuesta que
ROKI garantice.
Implementá la reversión así: probá primero la anulación; si se rechaza porque no es anulable o porque ya está liquidada, reembolsá en su lugar.
13.3 Anulación
POST /api/connect/v1/payments/{transaction_id}/void
{ "reason": "Customer cancelled" } # optional, max 2000 chars
Devuelve el pago con status: "voided". Los rechazos llegan como 422 bajo errors.void: ya
anulado, ya reembolsado (usá reembolso), no está en un estado anulable, o ya liquidado.
Una anulación también llena los campos de reembolso. Verificado en dos transacciones reales el 2026-08-14: después de anular, el pago lleva
{ "status": "voided", "refunded_amount": 25, "refund_status": "full" }
aunque no se reembolsó nada. Así que refund_status === 'full' no significa "esto fue
reembolsado" - es igual de cierto para una anulación. Ramificá según status (voided vs
refunded vs partially_refunded) y tratá los campos de reembolso como el monto devuelto al
tarjetahabiente por cualquier vía, no como evidencia de qué operación se usó. Un reporte que cuente
reembolsos por refund_status va a contar anulaciones como reembolsos sin avisar, y las dos son
comercialmente distintas: una anulación nunca llega al estado de cuenta del cliente, un reembolso sí.
El webhook payment.voided llegó como un segundo después en ambas transacciones, con los mismos campos.
13.4 Reembolso
POST /api/connect/v1/payments/{transaction_id}/refund
{ "amount": 500.00, "reason": "Partial return" }
amount es obligatorio, mínimo 0.01, hasta el monto reembolsable restante. Un reembolso parcial deja
partially_refunded; uno total pone refunded. 422 bajo errors.amount (debajo del mínimo, arriba
del restante) o errors.refund (transacción anulada, no reembolsable).
El reembolso funciona igual para una transacción creada por cualquier modo, incluido un checkout
embebido o un cobro con tarjeta guardada. No hay un endpoint de reembolso aparte para cobros con
token: usá acá como transaction_id el id que devolvió el cobro.
13.5 Recibos
GET /payments/{transaction_id}/receipt devuelve payment_id, transaction_id y un receipt_url
público. Agregá /download para el PDF. Los recibos sobreviven a una anulación o un reembolso
mientras el cobro original siga teniendo una transacción.
13.6 Una nota sobre los identificadores
Dos referencias distintas, y mezclarlas es el error más común:
- El
idde pago numérico es paraGET /payments/{id}. - El UUID
transaction_ides para anulación, reembolso y recibos.
Vale la pena guardar los dos cuando se cobra un pago. El listado (9.2) puede recuperar un id perdido, pero solo si sabés qué estás buscando.
