R-Transacciones SEPA: una referencia técnica
Rechazo, Devolución, Reembolso, Reversión. Cuatro eventos de ciclo de vida distintos con diferentes impactos en el libro mayor.
Entendiendo las R-Transactions SEPA: Guía Técnica para Ingenieros de Pagos
"El pago fue devuelto." En SEPA, esta frase puede significar cuatro cosas diferentes. Cada una tiene un activador diferente, una línea temporal PSD2 diferente, un ciclo de vida de settlement diferente y un tratamiento diferente en el ledger. La mayoría de las implementaciones las tratan como un único evento de "reversión" con un código de razón adjunto. Esto lleva a gestión incorrecta de períodos de retención, plazos PSD2 incumplidos y discrepancias de reconciliación que aparecen semanas después del hecho.
Las R-transactions SEPA no son un concepto. Son cuatro.
Cuatro Tipos, No Uno
| Tipo | Activador | Cuándo | Base Legal | Impacto en Ledger |
|---|---|---|---|---|
| Reject | Banco rechaza antes del settlement interbancario | D+1 (antes del settlement) | Rulebook EPC | Ninguno, no se movió dinero. Solo operaciones bancarias. |
| Return | Banco devuelve después del settlement, dentro del período de retención | D+5 (Core), D+2 (B2B) | PSD2 Art. 71 | Revertir el monto liquidado. Marcar RETURNED. |
| Refund | Pagador disputa después de que expira el período de retención | Hasta 8 semanas (Core), sin derecho (B2B) | PSD2 Art. 76 | Nuevo débito contra beneficiario. No es una reversión, es una reclamación nueva. |
| Reversal | Originador solicita cancelación después del settlement | Sin plazo fijo | camt.056 | Asiento de corrección (Stornobuchung según HGB §239). |
La distinción no es académica. Determina qué debe hacer el sistema con el dinero, cuándo debe hacerlo y cómo se ve el asiento del ledger.
Un Reject es silencioso desde la perspectiva del beneficiario. El pago nunca se liquidó. El banco del deudor lo rechazó pre-settlement (IBAN incorrecto, cuenta cerrada, cuenta bloqueada). El sistema del beneficiario puede que ni necesite saberlo, a menos que estuviera rastreando el pago entrante esperado.
Un Return es una reversión dentro del período de retención. El dinero fue liquidado (acreditado a la cuenta del beneficiario en el sistema de clearing), pero durante el período de retención el banco del deudor envía un return. El ledger del beneficiario debe revertir el crédito. Los fondos pasan de SETTLED_PENDING de vuelta al deudor.
Un Refund ocurre después de que el período de retención ha expirado y los fondos están SETTLED_AVAILABLE. El beneficiario tiene el dinero. El deudor disputa, dentro de 8 semanas para SEPA Core Direct Debit (PSD2 Art. 76), sin derecho de disputa para B2B. Un refund no es una reversión del asiento original. Es un nuevo débito separado contra el beneficiario. El asiento original permanece en el ledger, sin cambios e inmutable.
Un Reversal es iniciado por el originador (no el banco del deudor) vía una solicitud de cancelación camt.056. Esto típicamente ocurre cuando el originador descubre un duplicado o un error después del settlement. En contabilidad alemana, esto es una Stornobuchung, un asiento de corrección que referencia el original vía una foreign key correction_of. El asiento original permanece. El asiento de corrección lleva el mismo monto con signo opuesto.
Períodos de Retención y Ciclo de Vida de Settlement
Entre el settlement y la disponibilidad, los fondos pasan por un período de retención. La duración depende del esquema:
| Esquema | Período de Retención | Calendario |
|---|---|---|
| SEPA Débito Directo Core | 5 días hábiles TARGET2 | Calendario TARGET2 del BCE |
| SEPA Débito Directo B2B | 2 días hábiles TARGET2 | Calendario TARGET2 del BCE |
"Días hábiles" no son "días calendario." TARGET2 tiene su propio calendario de festivos: fines de semana, Año Nuevo, Viernes Santo, Lunes de Pascua, 1 de mayo, Navidad, 26 de diciembre. Los festivos nacionales alemanes que no son festivos TARGET2 no cuentan. Los festivos nacionales españoles que no son festivos TARGET2 no cuentan. El cálculo de días hábiles debe usar el calendario TARGET2, no un calendario nacional.
Durante el período de retención, los fondos están en estado SETTLED_PENDING. El saldo del beneficiario muestra el crédito, pero los fondos no están disponibles para retiro ni transferencia posterior. Después de que el período de retención expira, los fondos pasan a SETTLED_AVAILABLE. Los returns ya no son posibles (pero los Refunds sí, para Core DD).
Débito directo SEPA entrante acreditado al beneficiario.
Fondos visibles pero no disponibles para retiro. Returns posibles durante esta ventana.
Crédito revertido. Fondos vuelven al pagador. Settlement anulado.
Fondos liberados y disponibles. Returns ya no posibles.
Nuevo débito contra beneficiario. No es reversión, reclamación separada. Entrada original sin cambios.
Settlement completado. No más R-transactions posibles.
Los Códigos de Razón ISO Dirigen la Lógica
pacs.004 (Payment Return) lleva un campo ReasonCode de la enumeración ExternalStatusReason1Code. Esto no es texto libre. Es un conjunto cerrado definido por ISO 20022 y restringido por rulebooks del EPC.
El código de razón determina el tipo de R-transaction. El tipo determina la acción de settlement. La acción determina la línea temporal PSD2. La cadena es determinista.
| Código de Razón | Significado | Lógica de Clasificación |
|---|---|---|
| AC01 | Número de cuenta incorrecto | Pre-settlement → Reject; post-settlement → Return |
| AC04 | Cuenta cerrada | Return |
| AC06 | Cuenta bloqueada | Return |
| AM05 | Pago duplicado | Return |
| MD01 | Sin mandato (deudor niega) | Return |
| MS02 | Rechazo del deudor (sin razón) | Dentro de retención → Return; después → Refund |
| MS03 | Razón no especificada | Return |
| SL01 | Servicio específico del agente del deudor | Return |
| DUPL | Envío duplicado | Refund (iniciado por originador) |
| CUST | Solicitado por originador | Reversal (vía camt.056) |
| AGNT | Agente incorrecto | Reject (pre-settlement) |
| FOCR | Siguiendo solicitud de cancelación | Reversal (respuesta a camt.056) |
La función de clasificación:
classify(reason_code, within_holding_period) → tipo R-transaction
if pre_settlement(reason_code): → REJECT
if within_holding_period: → RETURN
if originator_initiated(reason_code): → REVERSAL
else: → REFUND
Cuando esta clasificación se implementa directamente sobre el código de razón ISO, sin tabla de mapeo intermedia, el manejo es determinista. Un nuevo código de razón en una versión futura del rulebook EPC requiere añadir una variante de enum. El compilador identifica cada handler que no lo cubre. Sin tabla de mapeo que actualizar. Sin deployment que sincronizar.
Arquitectura de Implementación
Tres responsabilidades, tres servicios. Cada uno es dueño de una preocupación.
Servicio de clasificación: recibe pacs.004 entrantes, extrae el código de razón, clasifica en Reject/Return/Refund/Reversal basado en el código y el estado de período de retención de la transferencia original.
Servicio de settlement: basado en el tipo clasificado, ejecuta la operación de ledger correcta:
- Reject: sin acción de ledger (la transferencia original nunca se liquidó).
- Return: anular el settlement pendiente. Transición de
SETTLED_PENDINGaRETURNED. - Refund: crear nueva transferencia de débito contra el beneficiario. El asiento original no se toca.
- Reversal: crear asiento de corrección (Stornobuchung) con referencia
correction_ofa la transferencia original.
Servicio de auditoría: registra cada R-transaction con: tipo, código de razón, referencia de transferencia original (resuelta por transfer_id → EndToEndId → external_id, cadena de fallback), plazo PSD2 e ID de evento DORA.
La transferencia original se resuelve a través de tres caminos de búsqueda:
- transfer_id directo (si la R-transaction lo lleva)
- Matching por EndToEndId (la referencia end-to-end ISO)
- Matching por external_id (la referencia del banco)
La cadena de fallback maneja la realidad de que no todos los mensajes pacs.004 llevan todos los campos de referencia. Algunos bancos llenan EndToEndId. Algunos usan su propia referencia externa. El sistema debe manejar los tres.
La Stornobuchung (Asiento de Corrección)
El derecho mercantil alemán (HGB §239) requiere que las correcciones a asientos del ledger se registren como nuevos asientos. Nunca como modificaciones del original. Nunca como eliminaciones.
Un Reversal no es DELETE FROM transfers WHERE id = original_id. Es:
INSERT INTO transfers (
debit_account_id, -- cuenta de crédito original (dirección invertida)
credit_account_id, -- cuenta de débito original (dirección invertida)
amount, -- mismo monto que el original
correction_of, -- FK → transferencia original
code, -- código de reversión
...
)
El asiento original permanece en el ledger. Inmutable. El asiento de corrección lo referencia. Un auditor ve ambos: la contabilización original y su corrección, vinculados por foreign key. El saldo del ledger refleja el efecto neto. La trilha de auditoría muestra el historial completo.
Esto no es una peculiaridad alemana. Es práctica contable sólida adoptada por cualquier sistema que toma la inmutabilidad en serio. Si el ledger permite modificaciones a asientos históricos, la trilha de auditoría no es confiable. Si las correcciones son nuevos asientos que referencian el original, la trilha es completa y a prueba de manipulación.
Lo Que Sale Mal en la Práctica
Tres errores de implementación comunes:
1. Tratar todas las R-transactions como reversiones. Un refund no es una reversión. Una reversión revierte el asiento original (contabilización de corrección). Un refund es una nueva reclamación que crea un nuevo débito. Confundirlos lleva a asientos de ledger incorrectos y cálculos de saldo incorrectos.
2. Usar días calendario para períodos de retención. Los períodos de retención SEPA se cuentan en días hábiles TARGET2. Un pago liquidado el miércoles antes de un festivo TARGET2 el jueves: el período de retención no cuenta el jueves. Usar días calendario significa liberar fondos demasiado pronto (riesgo regulatorio) o demasiado tarde (costo de liquidez).
3. Ignorar la distinción B2B vs. Core. SEPA Débito Directo B2B tiene un período de retención de 2 días y sin derecho de reembolso (el deudor no tiene reclamación bajo Art. 76). SEPA Core tiene un período de retención de 5 días y una ventana de reembolso de 8 semanas. Si el sistema aplica reglas Core a transacciones B2B, retiene fondos de más. Si aplica reglas B2B a transacciones Core, retiene de menos, y está expuesto a returns que no puede cubrir.
Leer más: Payments, Orquestación de Pagos | Connectivity, Financial Rails
Fuentes:
- European Payments Council: EPC016-06 (SEPA Core Direct Debit Rulebook, v2024.1)
- European Payments Council: EPC222-07 (SEPA B2B Direct Debit Rulebook)
- PSD2, Directiva 2015/2366, Art. 71 (Transacciones no autorizadas), Art. 76 (Derechos de reembolso para débitos directos)
- HGB §239, Código de Comercio alemán, requisitos para corrección de asientos contables
- Calendario TARGET2 del BCE (https://www.ecb.europa.eu/paym/target/target2/profuse/calendar/html/index.en.html)
- ISO 20022 ExternalStatusReason1Code, enumeración de códigos de razón pacs.004.001.11