# Initiate a Payout

Disburse funds directly to a customer's mobile money wallet or bank account. Payouts are processed asynchronously — the API queues the disbursement and notifies your server via webhook once the funds are settled.

* [ ] Mobile Money
* [ ] Bank Transfer

**How It Works**

Before initiating a payout, you may need to look up reference IDs depending on your disbursement method. Both flows share the same endpoint — only the request body differs.

1. **Fetch Prerequisites**

   For mobile money, call `GET /v1/countries` to get the `country_id`.\
   For bank transfers, also call `GET /v1/banks` to get the `bank_id`.
2. **Initiate the Payout**

   POST to `/v1/payment/payout/process` with the amount, destination, and transfer method. Vesicash queues the disbursement and returns a payout reference.
3. **Receive Webhook** \
   Vesicash sends a POST notification to your `webhook_url` when the payout status changes to successful or failed.

{% 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 — Common Parameters**

These parameters apply to **all payout types** regardless of transfer\_to value.

* amount (number): The amount to disburs.
* 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 disbursement method. Determines which additional fields are required.`mobile_number` ,`bank`
* webhook\_url (string):A publicly accessible HTTPS URL where Vesicash will POST the payout status notification.
* reason (string): The reason for the refund.

#### Additional Parameters by Transfer Type

The fields below are required depending on the value of `transfer_to`.

{% tabs %}
{% tab title="mobile\_number" %}
momo\_phone\_number (string): The mobile money phone number to receive the payout. Provide the full number in E.164 format — country code followed by the subscriber number, with no +, spaces, or dashes. E.g. `260999993000` instead of +`260999993000`
{% endtab %}

{% tab title="Tab 2" %}
bank\_id (string): The unique Vesicash identifier for the destination bank. Call `GET /v1/banks` to retrieve the list of supported banks and their IDs for the selected country.

account\_number (string): The recipient's bank account number. Must be a valid account number at the specified bank.
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**ℹ️ Fetching Bank IDs**

Use the `GET /v1/banks` endpoint with the relevant `country_id` to retrieve a list of available banks and their corresponding `bank_id` values before making a bank payout request.
{% endhint %}

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

{
    "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
}
```

```

//Bank Transfer Payout

{
  "amount": 123,
  "countryId": "zambia_country_id",
  "transfer_to": "bank",
  "bank_id": "zmb_zanaco_001",             // from GET /v1/banks
  "account_number": "1234567890",
  "webhook_url": "https://yourapp.com/webhooks/vesicash",
  "narration": "March commission payout"           // optional
}
```

#### Response

```
{
  "status": "success",
  "code": 200,
  "message": "payout queued successfully",
  "data": {
    "amount": 123,
    "message": "Payout is being processed by the provider",
    "reference": "PY_6c663231b************",  // store this to track the payout
    "status": "processing"                       // will update via webhook
  }
}
```

#### 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.                                                                                                       |
| data.reference | string | Unique payout reference assigned by Vesicash. Prefixed with PY\_. Use this to query the payout status endpoint or match incoming webhook events. |
| message        | string | Human-readable summary of the API response.                                                                                                      |
| data.status    | string | Current payout status. One of: `processing` `successful` `failed`                                                                                |
| data.amount    | string | The disbursement amount as received by Vesicash.                                                                                                 |

{% 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 payout is processed, Vesicash sends a POST request to your `webhook_url` with the final payout outcome. Use this event — not the initial API response — to update your system's refund state.

```
{
    "amount": 2,
    "business_id": "56b2f01d-75e4-46e4-b8ec-",
    "charge": 0,
    "created_at": "2026-03-05T09:52:55.410737Z",
    "currency": "GHS",
    "customer": {
        "email": "",
        "firstname": "",
        "lastname": "",
        "phone_number": "23320887******"
    },
    "environment": "live",
    "event": "payout_successful",
    "id": "31741038-9ae5-46e6-aeb3-",
    "method": "mobilemoney",
    "narration": "testing",
    "provider_transaction_id": "",
    "redirect_url": "",
    "reference": "PY_72f5985*****",
    "status": "successful",
    "type": "payout"
}
```

{% 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  | payout amount is less that 0                                    | The amount is zero, negative, or not a valid number.                        |
| 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  | Payout Provider service returned an error                       | The `momo_phone_number` is not a valid E.164 formatted mobile money number. |
