Saltar al contenido principal
Las transferencias intra-PSP (también llamadas P2P) son transferencias Pix donde el pagador y el beneficiario pertenecen al mismo participante — el ISPB de origen y el de destino son idénticos. Como el dinero nunca sale de la institución, estas transferencias se liquidan internamente en lugar de enrutarse a BTG para su liquidación. Aun así deben reportarse a BACEN por cumplimiento regulatorio.
Versiones anteriores del plugin rechazaban las transferencias intra-PSP con el error PIX-0406: Intra PSP Not Supported. Ese error fue eliminado — las transferencias y reembolsos intra-PSP ahora están totalmente soportados.

Detección


El plugin marca una transferencia como intra-PSP cuando el ISPB de destino es igual a tu PIX_ISPB configurado:
Tipo de iniciaciónFuente del ISPB de destino
KEY / QR_CODERespuesta de consulta DICT (account.participant)
MANUALdestination.ispb en el payload de la solicitud
Cuando se detecta, la respuesta de iniciación incluye isIntraPSP: true:
POST /v1/transfers/cashout/initiate
201 Created
{
  "id": "uuid",
  "status": "PENDING",
  "isIntraPSP": true,
  "expiresAt": "2026-02-25T12:05:00Z"
}
El flag isIntraPSP se propaga a las entidades Transfer, Cashout, Cashin y Refund para consulta y reconciliación.

Modelo de procesamiento


Las transferencias intra-PSP siguen el mismo enrutamiento de Midaz que las transferencias externas (a través de la cuenta de tránsito @external), por lo que el comportamiento del libro mayor es idéntico. La única diferencia es que la liquidación ocurre de forma síncrona dentro del plugin en lugar de a través de webhooks de BTG. Se crean dos transacciones de Midaz por transferencia:
  1. Cashoutsource → @external (pending: false)
  2. Cashin@external → destination (pending: false)
El cash-in interno reutiliza exactamente los mismos pipelines CashinApprovalCommand y CashinSettlementCommand que los cash-ins externos, incluyendo la validación de alias de CRM, las verificaciones de saldo, la titularidad de la clave PIX, la finalización del cobro y el cálculo de tarifas.

Flujo


Process Cashout (isIntraPSP = true)
  → Midaz debit: source → @external
  → Write inbound record to the webhook queue
  → Cashout status → PROCESSING (intermediary)
  → Return PROCESSING to client

Inbound worker (existing)
  → Picks up the record and delivers it (HTTP + HMAC)
    to POST /v1/payment/webhooks/intra-psp/events

Intra-PSP endpoint (orchestrates the full lifecycle)
  → CashinApprovalCommand → ACCEPTED / DENIED
  → ACCEPTED  → CashinSettlementCommand → Midaz credit → Cashout COMPLETED
  → DENIED / settlement fails → revert Midaz debit → Cashout FAILED
  → Report to BTG TRCK002 (async, non-blocking)
  → Outbound webhooks: cashout.completed/failed + cashin.completed
El cashout responde con PROCESSING, exactamente como un cashout externo a la espera de BTG. El estado final (COMPLETED/FAILED) se entrega de forma asíncrona vía webhook saliente. El endpoint intra-PSP es totalmente idempotente, por lo que los reintentos del worker nunca duplican transacciones.

Reporte regulatorio TRCK002


Cada transacción intra-PSP exitosa se reporta a BACEN a través del endpoint de abstracción TRCK002 de BTG, dentro del SLA regulatorio de P99 ≤ 300 segundos.
  • El reporte TRCK002 es no bloqueante — una falla de reporte nunca revierte la transacción de Midaz ni la finalización de la transferencia. Los reportes fallidos se reintentan con backoff exponencial.
  • BTG devuelve una entidad PixInternalTransactionsReport con un pactualId y un estado inicial de PROCESSING.
  • Las actualizaciones de estado del reporte llegan vía un webhook CAMT025 (PixInternalTransactionsReport) en el endpoint de eventos de BTG, transicionando el reporte a CONFIRMED o ERROR.
  • Como respaldo cuando se pierden webhooks, el estado del reporte se puede consultar por end-to-end ID o por identificación de devolución.

Reembolsos intra-PSP


Un reembolso (devolução) de una transferencia cuyo cash-in original fue intra-PSP también se procesa internamente:
  • El plugin detecta intra-PSP cuando el cash-in original tiene isIntraPSP = true.
  • Debita al solicitante del reembolso (requester → @external), luego orquesta el cash-in del reembolso al remitente original a través del mismo patrón de cola + endpoint.
  • El reembolso se reporta a TRCK002 con un returnIdentification.
  • Webhooks salientes: refund.completed/refund.failed al solicitante y cashin.completed al remitente original.
El desbloqueo no está soportado para transferencias intra-PSP. El flujo de desbloqueo consulta a BTG por el estado, lo cual no aplica a transacciones internas, por lo que llamarlo devuelve el error PIX-0418. Consulta Operaciones de reembolso.

Motivos de falla


Las fallas de validación de cash-in se entregan de forma asíncrona vía el webhook cashout.failed. Motivos comunes de falla intra-PSP:
CódigoDescripción
RECIPIENT_ACCOUNT_INVALIDFalló la validación de alias de CRM (cuenta no encontrada, cerrada, bloqueada)
RECIPIENT_CANNOT_RECEIVEFalló la validación de saldo del libro mayor
PIX_KEY_OWNERSHIP_INVALIDLa clave PIX no pertenece a la cuenta de destino
COLLECTION_INVALIDFalló la validación del cobro de QR code dinámico
INTERNAL_CREDIT_FAILEDFalló la transacción de crédito del libro mayor
INTERNAL_DEBIT_REVERT_FAILEDCrítico — falló la reversión del débito; requiere reconciliación manual

Próximos pasos