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

# Refunds

> Send money back to a payer: how refunds are scoped, how they move, and what they do to the payment.

A **refund** returns money to the person who paid you. In Kwugwo a
refund is attached to a single [activity](https://docs.kwugwo.africa/concepts.md#activity-how-an-ugwo-gets-charged),
the specific charge attempt that collected the money, rather than to
the ugwo as a whole. An ugwo can have several activities (an
abandoned bank transfer, then a successful USSD charge), and only the
one that succeeded holds funds to return.

Refund IDs look like `rfd.XXXX.YYYYYYYYYYYYYYYYYYYYYYYY`.

## At a glance

| | |
| - | - |
| Scoped to | One successful (or partially refunded) activity |
| Partial refunds | Yes, until the collected amount is exhausted |
| Minimum amount | The currency minimum (`20000` kobo = ₦200.00 for NGN) |
| Reversible | No. A refund cannot be cancelled once submitted |
| Settled by | The provider that took the payment |
| Endpoints | [Create](https://docs.kwugwo.africa/refunds/create.md) · [List](https://docs.kwugwo.africa/refunds/list.md) · [Get](https://docs.kwugwo.africa/refunds/get.md) |
| Webhooks | [`refund.created`, `refund.updated`, `refund.successful`, `refund.failed`](https://docs.kwugwo.africa/refunds/webhooks) |

## Lifecycle

Creating a refund records it and submits it to the provider in the
same request, so the response is normally `processing` rather than
`pending`.

| Status | Meaning | Terminal |
| - | - | - |
| `pending` | Recorded, not yet submitted. Rarely observed. | No |
| `processing` | Accepted by the provider and in flight. Most refunds sit here for hours or days. | No |
| `successful` | The money has gone back to the payer. | Yes |
| `failed` | The refund was rejected. `error` says why. | Yes |
| `cancelled` | Withdrawn before completion. Rare. | Yes |

You do not need to poll. Kwugwo follows the refund with the provider
and sends a [webhook](https://docs.kwugwo.africa/refunds/webhooks.md) as soon as it resolves. If a
refund is still `processing` after a couple of weeks, contact support
with its `uid`.

## What a refund does to the payment

A refund is counted against the activity as soon as it is created,
before the provider confirms it, so that a second request cannot
over-refund a payment while the first is still in flight:

* **On create**, the activity's `refunded_amount` rises and the
  activity becomes `partially_refunded`, or `refunded` once the full
  amount is covered.
* **If the refund fails**, `refunded_amount` is given back and the
  activity returns to `partially_refunded` or `successful`.

The ugwo mirrors its activity: `partially_refunded` while some of the
money is still yours, `refunded` once all of it has gone back. See
the [ugwo status table](https://docs.kwugwo.africa/concepts.md#ugwo-a-payment-request).

> [!WARNING]
>
> Treat `refunded_amount` as committed, not settled. For accounting,
> reconcile on the `refund.successful` webhook.

## How much you can refund

Leave `amount` out and Kwugwo refunds everything still refundable on
the activity: what the provider collected (`charged_amount`, falling
back to the activity's `amount`) less anything already refunded.

Pass `amount` for a partial refund. It must be at least the currency
minimum (`20000` kobo for NGN), and it cannot take the total past
what the activity collected.

## Providers

A refund goes back through the same provider that took the payment.
By default Kwugwo uses the connection the activity used; pass
`nzube_psp` to use a different connection for the same provider.

Not every provider supports refunds. When one does not, the refund
comes back `failed` with an `error.code` of `system_error`. Check
with support before building a flow on top of a provider you have not
refunded through before.

## Refunds for bank transfer and USSD payments

Some PSPs cannot send money back to the account that paid by bank
transfer or USSD, because they never saw it. For these, pass the
customer's bank account as `destination` when you [create the
refund](https://docs.kwugwo.africa/refunds/create.md):

```json theme={"system"}
"destination": { "provider": "gtb", "account_number": "0123456789" }
```

Without it, such refunds come back `failed` with an `error.message`
like `nzube.psp.paystack.error.missing_destination`. Sending it for
other mediums is harmless.

## Refunds created outside the API

A refund can also start at the provider, for example when someone
issues it from the provider's own dashboard. Kwugwo records it and
reports it exactly like any other refund, so:

* A `refund.created` webhook can arrive for a refund you never
  requested. Do not treat unknown refund IDs as an error.
* Its `ref` is `null`, since there was no API request to carry one.
* Its `amount` can be below the currency minimum.

## Idempotency

`ref` is unique per workspace, which makes it an idempotency key.
Send one on every refund and a duplicate request is rejected with
`409` instead of refunding twice.

If a create call times out, retry it with the same `ref`. Either the
first attempt never landed and you get a refund back, or it did and
you get `409`.

## The Refund object

Every field is documented on [The Refund object](https://docs.kwugwo.africa/refunds/object.md).

## Partial refunds in practice

A customer paid ₦5,000.00 (`500000` kobo) and returns two items worth
₦3,000.00.

1. Create a refund for `200000` with `"ref": "order_4719_refund_1"`.
   The activity becomes `partially_refunded` with
   `refunded_amount: 200000`.
2. Create a second for `100000` with a new `ref`. `refunded_amount`
   becomes `300000`; the activity stays `partially_refunded`.
3. Each refund resolves on its own and its webhooks can arrive in any
   order, so match on `data.uid` rather than arrival order.
4. To return the rest later, omit `amount`. The activity and the ugwo
   both become `refunded`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.