# Initiate a Refund

Initiate a refund for a previously completed transaction. Refunds are processed asynchronously — the response confirms the refund has been queued, and a webhook notification is sent once the funds are returned to the customer.

### How Refunds Work

Vesicash refunds are sent directly to the customer's mobile money wallet using the payment reference from the original transaction. Once queued, you can track the refund status via the status endpoint or listen for the webhook event.

{% hint style="info" %}
**Amount Constraint**

The refund amount must not exceed the original transaction amount. Partial refunds are supported — you may call this endpoint multiple times as long as the cumulative refunded amount does not exceed the original charge.
{% endhint %}

#### <mark style="color:green;">POST:</mark> /v1/payment/refunds/process

#### Headers

| Name       | Type   | Description              |
| ---------- | ------ | ------------------------ |
| secret-key | string | Your Vesicash secret key |
| public-key | string | Your Vesicash public key |

#### Request body

* amount (number): The amount to be refunded. This value must not be greater than the amount associated with the specified payment reference.
* payment\_reference (string): The reference of the payment that needs to be refunded. This should match the original payment reference.
* country\_id (string): The unique identifier for the country in which the transaction is being processed. To retrieve a valid `country_id`, call the [Get Countries endpoint](https://docs.vesicash.com/~/revisions/sUGfrlHe2F4873mAN9dv/get-countries) and use the `country_id` field from the matching country object in the response.
* transfer\_to (string): The destination type for the refund disbursement. Currently supports `mobile_number`.
* momo\_phone\_number (string): The mobile money number to receive the refund. E.164 format without the + prefix. E.g. 2340999993.
* webhook\_url (string): A valid HTTPS URL where Vesicash will POST the refund status notification once processing is complete. Must be publicly accessible. Overrides your dashboard default if provided.
* reason (string): The reason for the refund.

#### Request

For example, you can make a post request to the endpoint above and pass in the raw json data below to refund a successful transaction.

```
{
    "amount":1,
    "country_id":"{{ghana_country_id}}",
    "transfer_to":"mobile_number",
    "momo_phone_number": "{{phone_number}}",
    "payment_reference":"{{reference}}",
    "webhook_url": "{{webhook_url}}",
    "reason":"testing refund reason" //optional
}
```

#### Response

```
{
    "status": "success",
    "code": 200,
    "message": "refund queued successfully",
    "data": {
        "status": "pending",
        "message": "refund queued successfully",
        "reference": ""
    }
}
```

#### Response Fields

| Field          | Type   | Description                                                                                                            |
| -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- |
| status         | string | Top-level outcome of the API call. `success` or `error`.                                                               |
| code           | number | HTTP status code mirror. `200` on success.                                                                             |
| message        | string | Human-readable summary of the API response.                                                                            |
| data.status    | string | Current refund status. One of: `processing` `successful` `failed`                                                      |
| data.reference | string | Unique refund reference assigned by Vesicash. Use this to poll the refund status endpoint or correlate webhook events. |

{% hint style="info" %}
Store the data.reference returned in the response. You can use it to query the  [status endpoint](https://docs.vesicash.com/~/revisions/B4WbZDJmrvuixkS1SN5C/api-documentation/payments/get-payment-details) or match it against incoming webhook payloads.
{% endhint %}

### Webhook Notification

Once the refund is processed, Vesicash sends a POST request to your webhook\_url with the final refund outcome. Use this event — not the initial API response — to update your system's refund state.

```
{
    "amount": 0.1,
    "business_id": "56b2f01d-75e4-46e4-b8ec-",
    "charge": 0,
    "created_at": "2026-02-26T14:59:47.228153Z",
    "currency": "GHS",
    "customer": {
        "email": "",
        "firstname": "",
        "lastname": "",
        "phone_number": "233208******"
    },
    "environment": "live",
    "event": "refund_successful",
    "id": "5f8c954e-9428-44b7-8966-",
    "method": "mobilemoney",
    "narration": "testing refund reason",
    "provider_transaction_id": "",
    "redirect_url": "",
    "reference": "",
    "status": "successful",
    "type": "refund"
}
```

{% hint style="info" %}
**✓ Signature Verification**

Always verify the X-Vesicash-Signature header on incoming webhooks using your webhook secret before updating any records. Discard requests with invalid signatures.
{% endhint %}

### Error Codes

| HTTP | Mesage                                                          | Description                                                                                         |
| ---- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| 400  | Refund amount exceeds the remaining refundable balance          | The refund amount is zero, negative, or exceeds the refundable balance on the original transaction. |
| 400  | payment not found                                               | The `payment_reference` does not match any transaction in your account.                             |
| 400  | Insufficient funds or wallet error preventing refund processing | I                                                                                                   |
| 400  | Refund Provider service returned an error                       | The `momo_phone_number` is not a valid E.164 formatted mobile money number.                         |
