# Refund a Payment

The Get Mini framework provides two ways to return funds to customers: standard refunds (linked to a previous transaction) and stand-alone refunds (without the original transaction reference).

## Requirements

Before you begin, ensure you have verified permissions and data availability. The merchant must have permission for refunds (100201) and, for stand-alone refunds, the specific `permiteDevolSinOrigin` flag enabled. For standard refunds, you must possess the original `OperacionDTO` or the `identificadorRTS`. Critically, stand-alone refunds require the customer to be physically present with their card to complete the transaction on the PIN pad.

## Option 1: Standard Refund

Standard refunds are linked to a previous transaction in your history. You use the `RedsysTransactionManager` to process these via Web Service.

### Step 1: Obtain the Original Operation
To initiate a linked refund, you must first retrieve the `OperacionDTO` object corresponding to the original transaction. You can do this by querying the transaction history.

```
// 1. Configure the search query
let userInfo = RedsysUserInfoManager.getInfo(user)
let dateFrom = Date().addingTimeInterval(-86400 * 30) // e.g., last 30 days
let dateTo = Date()

// 'termTPVPC' is of type TerminalDataDTO (Type 2 for PC Terminal)
let consulta = ConsultaFechasDTO(
    terminal: termTPVPC,
    dateInitial: dateFrom,
    dateEnd: dateTo,
    andPage: 0,
    andUserInfo: userInfo
)

// 2. (Optional) Apply filters to find specific transaction
let filtros = ConsultaFechasDTOFiltros()
filtros.setResultado("AUTORIZADAS")
filtros.setTipoOperacion("PAGO")
filtros.setFactura("INV-001") // Filter by your Invoice ID

// 3. Execute query
RedsysTransactionManager.peticionConsultaFechaPagina(
    consulta,
    conValores: filtros.dictValores()
) { (result, error) in
    if let result = result, let operations = result.operaciones as? [OperacionDTO] {
        // Find the specific operation object needed for the refund
        if let originalOp = operations.first {
             print("Found operation: \(originalOp.numAutorizacion)")
             // Proceed to Step 2 with 'originalOp'
        }
    }
}
```

### Step 2: Initiate the Refund
Use `peticionDevolucion` with an `EnvioDevolucionDTO` object.

```
// 1. Setup User Info
let userInfo = RedsysUserInfoManager.getInfo(user)

// 2. Setup the Refund Object (using an existing OperacionDTO)
// Assuming 'termTPVPC' is your TerminalDataDTO and 'operacionOriginal' is OperacionDTO
let devolucion = EnvioDevolucionDTO(
    terminal: termTPVPC,
    andOperacion: operacionOriginal,
    andUserInfo: userInfo
)

// 3. Set the amount (e.g., "10.00")
devolucion.importedevol = "10.00"

// 4. Execute
RedsysTransactionManager.peticionDevolucion(devolucion) { (result, error) in
    if let result = result {
        print("Refund successful: \(result)")
    } else if let error = error {
        print("Refund error: \(error.localizedDescription)")
    }
}
```

<Callout type="note">

For refunds between different merchants in the same group, use the extended constructor including `ComercioOriginal`, `FechaOperacion`, and `NumAutorizacion`.

</Callout>

## Option 2: Refund Without Original (Stand-alone)

If you do not have the original transaction details or are processing a manual return, use the Bluetooth Refund method. This requires the customer to present their card to the PIN pad.

### Step 1: Execute the Refund
Create an `EnvioDevolucionSinOriginalDTO` with the amount in cents and execute it using the PIN pad Manager.

```
// Amount in cents (e.g., 10.00€ = 1000)
// 'termTPVPC' is your TerminalDataDTO
let devolucionSinOriginal = EnvioDevolucionSinOriginalDTO(
    terminal: termTPVPC,
    andImporteDevolucion: "1000",
    forFactura: "INV-001"
)

// Execute using the Pinpad Manager
// Assuming 'pinpadElegido', 'merchanElegido', and 'pinpadConfig' are initialized
pinpadManager.devolucionBluetooth(
    pinpadElegido,
    merchan: merchanElegido,
    config: pinpadConfig,
    andDevolucionDTO: devolucionSinOriginal,
    withDelegate: self
)
```

### Step 2: Handle PIN pad Callbacks
You must implement `onPaymentFinished` (or specific refund delegate method if applicable for your delegate version) to receive the result, which will be returned as a `DevolucionResponseDTO`.

## Refund Constraints and Errors

| Constraint | Description |
| :---- | :---- |
| **Amount Limit** | A standard refund cannot exceed the original transaction amount (Error Code 200: TPV-PC0009). |
| **Permission** | Stand-alone refunds must be enabled in the merchant profile (`permiteDevolSinOrigin`). |
| **Transaction State** | You can only perform a refund on operations with an Estado of "F" (Finalized). |

## Troubleshooting

**Error Code 200 (TPV-PC0009)**
The refund amount exceeds the original transaction amount. Verify the remaining balance of the original order if partial refunds were previously issued.

**Error Code 262 (TPV-PC0100)**
The specific operation type does not allow a refund (e.g., attempting to refund a transaction that hasn't settled yet or is already annulled).

**Merchant Permissions**
If a stand-alone refund fails immediately, check `PerfilComercioManager` to see if `permiteDevolSinOrigin` is YES.

## Next Steps

- [Create a Single-Step Payment](/en/get-mini/ios-sdk/guides/single-step-payment-ios) - Standard sale transactions
- [Create a Payment with Installments](/en/get-mini/ios-sdk/guides/create-installments-ios) - Handle currency and financing options
- [Initialize the SDK](/en/get-mini/ios-sdk/guides/initialize-ios-sdk) - Set up SDK configuration