# Refund a Payment

A referenced refund uses the original payment’s reference so the refund is directly linked to the initial sale, ensuring accurate reconciliation and audit tracking.

If you don't have, or don't want to use, the original payment's reference, use an [Unreferenced Refund](./unreferenced-refund.md) instead, but be aware that it can fail more often, so use it only as a last resort.

```admonition
icon: fas fa-warning-triangle
title: Note
content: It is recommended that your ePOS application provides a controlled way to issue refunds (e.g., manager PIN or role-based permissions) to prevent unauthorized refunds.
```

## Prerequisites

- You must have initialized the SDK and obtained a valid `TeyaCommonTransactionsApi` instance. See [Getting Started](/epos-sdk/poslink/ios/getting-started#5-set-up-the-sdk).
- Store the `gatewayPaymentId` from a successful payment state. See [Make Payment](/epos-sdk/poslink/ios/make-payment).

```admonition
icon: fas fa-info-circle
content: The `gatewayPaymentId` is provided in `TeyaPaymentStateDetails` when a payment reaches a final successful state. Persist it in your app to support refunds later.
```

## Make a referenced refund

Call `refundPayment` on your `TeyaCommonTransactionsApi` instance, passing the original `gatewayPaymentId`, the `amount` to refund, and the `currency`.

```swift
import Foundation
import TeyaUnifiedEposSDK

let amountToRefund: Int32 = 100 // minor units (e.g., cents)
let currency = "GBP"          // ISO 4217

let refundSubscription = teyaPosLinkSDK.transactionsApi.refundPayment(
    paymentId: originalSuccessfulPaymentId, 
    amount: amountToRefund,
    currency: currency
)
```

```admonition
icon: fas fa-warning-triangle
title: Partial refunds
content: |
    You must always specify the `amount` because partial refunds are supported. For example, if the original payment was £2.99, you may refund £1.00.
    The refund `amount` cannot exceed the original captured amount or the remaining refundable balance.
```

## Listen for refund result

Subscribe to the refund result using `TeyaRefundResultListener`. You’ll receive a single callback once the refund completes (either successful or failed).

Create a small Swift wrapper for convenience:

```swift
private class RefundResultListener: TeyaRefundResultListener {
    private let onResult: (TeyaRefundResultDetails) -> Void

    init(onResult: @escaping (TeyaRefundResultDetails) -> Void) {
        self.onResult = onResult
    }

    func onRefundResult(refundResult: TeyaRefundResultDetails) {
        onResult(refundResult)
    }
}
```

Subscribe to the refund result:

```swift
refundSubscription.subscribe(listener_: RefundResultListener { refundResult in
    // Inspect refundResult and update your UI
    print("Refund result: \(refundResult)")
})
```

`TeyaRefundResultDetails` contains a refund id (if successful), a `debugErrorMessage` (optionally) and the result which can be:

| Name |
|------|
| `SUCCESS` |
| `INVALID_AMOUNT_OR_PAYMENT_ID` |
| `AMOUNT_EXCEEDS_ALLOWED` |
| `DECLINED` |
| `NETWORK_ERROR` |
| `CANCELLED` |
| `FAILED` |


```admonition
icon: fas fa-info-circle
content: The SDK currently does not provide a built-in UI for refunds. We recommend showing your own progress indicator and final status based on the refund callback.
```
