> For the complete documentation index, see [llms.txt](https://docs.vesicash.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.vesicash.com/api-documentation/payments/initiate-a-refund.md).

# 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 based on the original payment method:

* **Mobile Money** → refunded to customer wallet
* **Card** → refunded back to the customer’s card

{% 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: required): The amount to be refunded. This value must not be greater than the amount associated with the specified payment reference.
* payment\_reference (string: required): The reference of the payment that needs to be refunded. This should match the original payment reference.
* transfer\_to (string:required): The destination type for the refund disbursement. Currently supports `mobile_number` and `card`
* country\_id (string :optional for `mobile money`): 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.
* momo\_phone\_number (string:required for `mobile money`): The mobile money number to receive the refund. E.164 format without the + prefix. E.g. 2340999993.
* webhook\_url (string:optional): 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: optional): 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.

```
//Mobile Money Refund

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

//Card Refund (NEW)
{
  "amount": 1,
  "payment_reference": "PY_VM_8*******",
  "transfer_to": "card",
  "webhook_url": "https://example.com/webhook",
  "reason": "Customer requested refund"
}
```

#### 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.                         |
