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

# Payin Reversal

A **payin reversal** is a system-initiated refund triggered automatically by Tazapay when an automated payer name verification check determines the payer identity does not match the buyer's declared identity. It is distinct from a merchant-initiated refund — no action is required from the merchant.

## How It Works

After PSP payment approval on eligible push-based APMs (PayNow, PIX, UPI, Promptpay), Tazapay runs a name match check comparing the name the buyer provided at checkout against the name returned by the PSP.

| Match Result    | Outcome                                                    |
| :-------------- | :--------------------------------------------------------- |
| `FULL_MATCH`    | Payment proceeds to `succeeded` — normal flow              |
| `PARTIAL_MATCH` | Payment proceeds to `succeeded` — normal flow              |
| `NO_MATCH`      | Payin moves to `reversed` — refund automatically initiated |

When the result is `NO_MATCH`, Tazapay:

1. Sets the payment attempt and payin status to `reversed` (terminal state)
2. Automatically creates and submits a full refund to the PSP
3. Sends email notifications to the buyer (and optionally the merchant)
4. Fires a `payment_attempt.reversed` webhook event

## Eligibility

The name match check only runs when **all** of the following are true:

* The payment method is a push-based APM in Tazapay's risk-check allowlist
* The PSP returns a `payer_name` in its success callback
* The merchant has **Name Match Check** enabled (configured via Tazapay Ops dashboard)
* The customer's total payin volume over the trailing 30 days exceeds the configured threshold (default: **0 USD**, meaning every eligible transaction is checked)

## Refund Details

The reversal refund is created with the following properties:

| Field          | Value            |
| :------------- | :--------------- |
| `source`       | `payin_reversal` |
| `reason`       | `Payin Reversal` |
| `initiated_by` | `system`         |
| `fee_bearer`   | `tazapay`        |

* The refund is always for the **full transaction amount**
* Tazapay bears both the payin processing fee and the refund processing fee — **no fees are charged to the merchant or the buyer**
* The net merchant balance impact is zero

## Balance Impact

Funds flow through the merchant balance even for reversed transactions to maintain ledger consistency:

1. **Payin credit** — merchant balance is credited (same as `succeeded`)
2. **Refund debit** — full amount is immediately debited back via the system refund

The net result is a zero-sum movement with no change to the merchant's available balance.

## Webhook Events

| Event                      | Description                                                 | Default |
| :------------------------- | :---------------------------------------------------------- | :------ |
| `payment_attempt.reversed` | Fired when the payment attempt status changes to `reversed` | On      |
| `refund.created`           | Fired when the system refund is created for the reversal    | Off     |

The `refund.id` is only available in the `refund.created` webhook payload. It is not included in the `payment_attempt.reversed` payload or the Get Payin response. Enable `refund.created` and capture the refund ID from that event if you need to track refund status via `GET /v3/refund/{refund_id}`.

## API Changes

The `GET /v3/payin/{id}` response includes two new fields for reversed payins:

| Field                   | Type                   | Description                                                                                          |
| :---------------------- | :--------------------- | :--------------------------------------------------------------------------------------------------- |
| `reversed_at`           | string (ISO timestamp) | Timestamp when the payin was reversed. `null` unless `status` is `reversed`.                         |
| `risk_check`            | object / null          | Risk check result that determined the terminal state. `null` when no name match check was performed. |
| `risk_check.result`     | string                 | Match outcome: `FULL_MATCH`, `PARTIAL_MATCH`, `NO_MATCH`                                             |
| `risk_check.buyer_name` | string                 | Name provided by the buyer at checkout.                                                              |
| `risk_check.payer_name` | string                 | Name returned by the PSP after payment.                                                              |
| `risk_check.checked_at` | string (ISO timestamp) | Timestamp when the risk check was performed.                                                         |

## Notifications

| Recipient | Channel                              | Configurable                                              |
| :-------- | :----------------------------------- | :-------------------------------------------------------- |
| Buyer     | Email                                | No — always sent                                          |
| Merchant  | Email                                | Yes — requires email event to be enabled at account level |
| Merchant  | Webhook (`payment_attempt.reversed`) | Yes — enabled by default                                  |

The buyer receives an email notifying them that their payment was reversed and a full refund has been initiated.
