> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Intra-PSP transfers

> How the Pix Indirect Plugin via BTG settles intra-PSP (P2P) transfers and refunds internally without BTG settlement, while reporting to BACEN via TRCK002.

An intra-PSP transfer (also called P2P) is a Pix transfer between a payer and a payee at the **same participant**. The source and destination ISPB are identical. The money never leaves the institution, so the plugin settles the transfer internally and does not route it to BTG. The plugin still reports the transfer to BACEN for regulatory compliance.

<Note>
  The plugin supports intra-PSP transfers and refunds. It settles them internally and reports each one to BACEN through TRCK002.
</Note>

# Detection

***

The plugin marks a transfer as intra-PSP when the destination ISPB matches your configured `PIX_ISPB`:

| Initiation type   | Source of destination ISPB                   |
| ----------------- | -------------------------------------------- |
| `KEY` / `QR_CODE` | DICT lookup response (`account.participant`) |
| `MANUAL`          | `destination.ispb` in the request payload    |

Detection is internal. The initiation response and the cashout status match an external transfer. The plugin routes an intra-PSP transfer through the internal settlement path instead of BTG.

# Processing model

***

An intra-PSP transfer uses the same Midaz routing as an external transfer, through the `@external` transit account. The ledger behavior is identical. The plugin settles the transfer synchronously and does not wait for BTG webhooks.

The plugin creates two Midaz transactions per transfer:

1. **Cashout** — `source → @external` (`pending: false`)
2. **Cashin** — `@external → destination` (`pending: false`)

The internal cash-in reuses the same `CashinApprovalCommand` and `CashinSettlementCommand` pipelines as an external cash-in. These pipelines run CRM alias validation, balance checks, Pix key ownership, collection completion, and fee calculation.

## Flow

***

```
Process Cashout (intra-PSP detected)
  → 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/intra-psp/transfers/webhooks

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
```

<Note>
  The cashout responds with `PROCESSING`, like an external cashout that waits for BTG. The plugin delivers the final status (`COMPLETED` or `FAILED`) asynchronously through an outbound webhook. The intra-PSP endpoint is idempotent, so worker retries never duplicate transactions.
</Note>

# TRCK002 regulatory reporting

***

The plugin reports every successful intra-PSP transaction to BACEN through BTG's **TRCK002** endpoint.

* TRCK002 reporting is **non-blocking**. A report failure never rolls back the Midaz transaction or the transfer completion. The plugin retries a failed report.
* The plugin creates a `TransactionReport` for each transaction. After BTG accepts the submission, the report status becomes `PROCESSING` and carries a `pactualId`.
* BTG sends report status updates through a **CAMT025** webhook, typed `PIX_INTERNAL_TRANSACTIONS_REPORT`. The webhook moves the report to `CONFIRMED` (terminal) or `ERROR` (recoverable).
* You can also query a report by end-to-end ID or return identification when a webhook does not arrive.

# Intra-PSP refunds

***

The plugin also processes a refund internally when the original cash-in was intra-PSP:

* The plugin detects intra-PSP from the original transfer, when its source and destination ISPB match.
* It debits the refund requester (`requester → @external`). It then delivers the refund cash-in to the original sender through the same queue and endpoint pattern.
* The plugin reports the refund to TRCK002 with a `returnIdentification`.
* The plugin persists a `REFUND` outbound webhook (DICT flow) to notify the requester, and the intra-PSP cash-in settlement queues `cashin.completed` for the original sender.

<Warning>
  Do not call unblock for an intra-PSP transfer. The unblock flow queries BTG for the transfer status. BTG never processes an internal transaction, so the query does not apply. See [Refund operations](/en/rails/pix/btg/indirect-pix-refund-operations).
</Warning>

# Failure reasons

***

The plugin delivers a cash-in validation failure asynchronously through the `cashout.failed` webhook. For an intra-PSP failure, the webhook carries the reason `INTRA_PSP_REJECTED` and a sanitized message. Common messages:

| Message                                      | Meaning                                                 |
| -------------------------------------------- | ------------------------------------------------------- |
| `pix key not found`                          | The Pix key does not exist in DICT.                     |
| `pix key is not active`                      | The Pix key exists but is inactive.                     |
| `pix key does not match account`             | The Pix key does not belong to the destination account. |
| `account cannot receive payment`             | The destination account cannot receive the payment.     |
| `collection validation rejected the payment` | The dynamic QR code collection rejected the payment.    |
| `duplicate transaction`                      | A cash-in with the same end-to-end ID already exists.   |

# Next steps

***

* [Webhooks](/en/rails/pix/btg/indirect-pix-webhooks) — Event envelope, retries, and routing
* [Refund operations](/en/rails/pix/btg/indirect-pix-refund-operations) — Distributed refunds and unblocking
* [Setting up the integration](/en/rails/pix/btg/indirect-pix-integration) — ISPB and worker configuration
* [API reference](/en/reference/midaz/plugins/indirect-pix/create-entry) — Full API documentation
