Payout API

Payouts on Kora are done using our RESTful APIs, enabling a smooth, solid integration.

If a payout request is triggered, Kora will directly disburse from your positive balance, and notify your application via an API callback when the transfer has been completed.

Furthermore, you can always get the status of a single payout at any time via API or monitor the transaction status on the dashboard, where you can also see the payment details with a reference number for the transaction.


Use Case

Let's consider a typical case where your service uses a company eWallet to pay customers, employees, etc.

On your website when a customer requests a payout to their bank account. Your website’s back-end asks Kora to process this payout. Kora processes the payment to the customer’s bank account, then notifies your website’s back-end when the payout has been completed. Easy peasy!

Let's take a quick look at how you'll use the Kora API to implement the workflow for this use case. First, we'll look at your high-level workflow. Then we'll explain how to implement the workflow in detail. We'll use a sample code to bring the workflow to life.

Workflow - Payout to customer’s bank account

This is what the workflow would look like from a birds-eye view.


Stage 1 - Requesting a Payout

  1. On your website, a payout request is made by a customer.
  2. Your website back-end asks Kora to process the payout.

Stage 2 - Processing the Payout

  1. Kora processes the payout.
  2. The customer's bank account is credited with funds from the merchant’s eWallet.
  3. Your Kora dashboard or application is notified that the money was credited to the bank account

Implementing the Payout Workflow

Now, let’s dive deeper into how this workflow would be implemented end-to-end.

Step 1 - Use List banks API to get valid bank codes, or use List MMO API to get valid mobile money operator slugs.

Step 2 - Verify the destination bank account - Optional

Step 3 - Request payout

Step 4 - Receive confirmation via webhook when the payout is completed

Step 5 - Query the transaction to get the status of the transaction.

📘

Before you start:

Make sure to check out Quick Start learn more about Test and Live Modes, as well as API keys and how to use them.


1 - Find bank codes from List Banks or mobile money operators slug from List MMO

For a successful payout, you need to input the destination bank of the transaction in the bank field. This means you need to get details of the direct bank for that beneficiary (e.g, Access Bank, ABSA or Wema Bank, etc).

In this example, you'll find the different bank types that allow transfers in the currencies that we support.

Request Banks Type

Request for a list of all available bank codes for transfers in Nigeria, Kenya and South Africa.

{{baseurl}}/merchant/api/v1/misc/banks?countryCode=NG
{{baseurl}}/merchant/api/v1/misc/banks?countryCode=KE
{{baseurl}}/merchant/api/v1/misc/banks?countryCode=ZA

Banks Type response

This is an example response to the request for bank type

{
  "status": true,
  "message": "success",
  "data": [
    {
      "name": " Bank name", // e.g Access Bank Nigeria
      "slug": " Bank slug", // e.g access
      "code": " Bank code", // e.g 044
      "country": "NG"
    },
  ]
}
{
  "status": true,
  "message": "success",
  "data": [
    {
      "name": "ABC Bank", // e.g ABC Bank Kenya
      "slug": " Bank slug", // e.g abc-bank-ke
      "code": " Bank code", // e.g 0035
      "country": "KE"
    },
  ]
}
{
  "status": true,
  "message": "success",
  "data": [
    {
      "name": "Bank Name", // e.g ABSA
      "slug": " Bank slug", // e.g absa-za
      "code": " Bank code", // e.g 632005
      "country": "ZA"
    },
  ]
}

For a successful mobile money payout, you need to input the mobile money operator slug of the transaction in the mobile_money.operator field. This means you need to get details of the beneficiary's mobile money operator. For example, Safaricom (Mpesa) or Airtel.

In this example, you'll find the different mobile money operator types that allow transfers in the currencies supported on Kora.

Request Mobile Operator Type (Kenya)

Request for a list of all available mobile operators enabled for transfers in Kenya and their payout limits.

{{baseurl}}/merchant/api/v1/misc/mobile-money?countryCode=KE

Here's an example response to the request for mobile money type:

{
  "status": true,
  "message": "success",
  "data": [
    {
      "name": " Mobile money operator name", // e.g Safaricom
      "slug": " Mobile money operator slug", // e.g safaricom-ke
      "code": " Mobile Money code", // e.g 0001
      "country": "KE",
      "min":  10,
      "max": 70000
    },
  ]
}

Request Mobile Operator Type (Ghana)

Request for a list of all available mobile operators enabled for transfers in Ghana and their payout limits.

{{baseurl}}/merchant/api/v1/misc/mobile-money?countryCode=GH

Here's an example of the response to a request for mobile money type:

{
  "status": true,
  "message": "success",
  "data": [
    {
      "name": " Mobile money operator name", // e.g MTN
      "slug": " Mobile money operator slug", // e.g mtn-gh
      "code": " Mobile Money code", // e.g 0004
      "country": "GH",
      “min”:  10,
      “max”: 100000
    },
  ]
}

2 - Verify the destination bank account - Optional

Bank account verification for Nigerian and Kenyan Banks

Use Bank Account Resolve API to resolve the bank accounts (Kenya and Nigeria) before you request the payout. See the Verification request and response below.

Bank Account Resolve request

This resolves the bank account:

{{baseurl}}/merchant/api/v1/misc/banks/resolve

Request body

The following parameters should be included in the request body.

FieldData TypeDescription
bankStringRequired - bank code of account number
accountStringRequired - account number to be resolved
currencyStringRequired - country currency. E.g, KE, NG.

Bank Account Resolve response

Here’s how the response should look like.

{
  "status": true,
  "message": "Request Completed",
  "data": {
    "bank_name": "United Bank for Africa",
    "bank_code": "033",
    "account_number": "2158634852",
    "account_name": "EBUKA CIROMA OLADEMJI"
  }
}

Mobile Money account verification for Ghanaian mobile money networks

Use the Mobile Money Account Resolve API to resolve the mobile money account before you request the payout. See the request and response below.

Mobile Money Account Resolve request

{{baseurl}}/merchant/api/v1/misc/mobile-money/resolve

Request body

The following parameters should be included in the request body.

FieldData TypeDescription
mobileMoneyCodeStringRequired - code for mobile money operator
phoneNumberStringRequired - phone number to be resolved
currencyStringRequired - country currency. E.g, GH.

Response

Here’s how the response should look like.

{
  "status": true,
  "message": "Request Completed",
  "data": {
    "mobile_money_operator": "MTN GH",
    "mobile_money_code": "0004",
    "phone_number": "233722222222",
    "account_name": "EBUKA CIROMA OLADEMJI"
  }
}

3 - Check availability of Bank or Mobile Money network (MMN) - Optional

Use the Availability API to confirm a bank or Mobile Money network availability before you request the payout. See the request and response below.

ℹ️

Please note that this service is currently only available for South African payouts.

Bank or Mobile Money Availability

{{baseurl}}/merchant/api/v1/payouts/availability

Request Body

FieldData TypeDescription
typeStringRequired - payment method e.g bank_account, mobile_money
currencyStringRequired - country currency. E.g, ZAR.

Response

Here's an example of what a response would look like:

{
  "status": true,
  "message": "Request Completed",
  "data":
  {
    "name": "ABSA",
    "slug": "absa-za",
    "code": "632005",
    "nibss_bank_code": null,
    "country": "ZA",
    "status": "delayed"
  },
  {
    "name": "African Bank",
    "slug": "african-bank-za",
    "code": "430000",
    "nibss_bank_code": null,
    "country": "ZA",
    "status": "delayed"
	}
}

Availability statuses and meaning

  • If the response returned is Available, your payout request will be processed instantly.
  • If the response returned is Delayed, your payout request will not be processed instantly due to delay from the Bank or Mobile Money network but it will be processed at a later time.
  • If the response returned is Unavailable, your payout request will not be processed within the period the request is made due to a possible downtime from the Bank or Mobile Money network.

4 - Request Payout

For this, you'll use the Payout API.

Payout Request

{{baseurl}}/merchant/api/v1/transactions/disburse

You need to find the required field for each payout request.

FieldData TypeDescription
referenceStringRequired - unique transaction reference
destinationObjectRequired
destination.typeStringRequired - can be bank_account or mobile_money
destination.amountNumberRequired - transaction amount in two decimal places.
destination.currencyStringRequired - transaction amount currency e.g. NGN, KES.
destination.narrationStringOptional - transaction narration or description
destination.bank_accountObjectRequired - if destination type is bank_account
destination.bank_account.bankStringRequired - recipient bank code. Some bank codes that you can use to simulate successful transactions in Test mode are 044, 033, 058 (i.e.for Access Bank, UBA and GTCO respectively). See the bank details for other test scenarios here.
destination.bank_account.accountStringRequired - recipient account number
destination.bank_account.account_nameStringRequired - if currency is ZAR
destination.mobile_moneyObjectRequired - if destination type is mobile_money
destination.mobile_money.operatorStringRequired - if destination.type is mobile_money, the mobile money operator slug, eg. safaricom-ke.
destination.mobile_money.mobile_numberStringRequired - if destination.type is mobile_money, the mobile number attached to the mobile money account.
destination.customerObjectRequired
destination.customer.nameStringOptional - Customer Name
destination.customer.emailStringRequired - Customer Email
metadataObjectOptional - It takes a JSON object with a maximum of 5 fields/keys. Empty JSON objects are not allowed.

Each field name has a maximum length of 20 characters. Allowed characters: A-Z, a-z, 0-9, and -.

Handling Unexpected Request Errors

When you initiate a payout, DO NOT treat request errors such as 502 Bad Gateway, 504 Gateway Timeout, 503 Service Unavailable, 500 Internal Server Error, etc, as failed payout. If you receive any of the errors or any other unexpected error, we strongly recommend that you verify the payout using the Payout Verification API before giving value or completing the transaction.

Whenever an unexpected request error occurs, it’s possible that the payout may have been accepted and processed by Kora. Following this recommendation will prevent the possibility of a financial loss.

You can find a list of possible payout errors and how to treat them here.

🚧

Verifying the payout before completing the transaction and providing value to the customer is strongly recommended. Please note that Kora will not be liable for any loss resulting from these errors.

Payout Response

Here’s how the response for your payout request should look like:

{
  "status": true,
  "message": "transfer initiated successfully",
  "data": {
    "amount": "100.00",
    "fee": "2.50",
    "currency": "NGN",
    "status": "processing",
    "reference": "KPY-D-t74azVrw9oPLtv9",
    "narration": "Test Transfer Payment",
    "message": "Payout processing",
    "customer": {
      "name": "John Doe",
      "email": "[email protected]",
      "phone": null
    },
    "metadata": {
      "internalRef": "JD-12-67",
      "age": 15,
      "fixed": true,
    }
  }
}

Payout History API

The Payout History API allows you to fetch all the payout transactions made from your Kora account without having to get them from the dashboard. Use the endpoint below to fetch your payout history. (NOTE: It accepts your secret key as the authorization header)

{{baseurl}}/merchant/api/v1/payouts

The parameters for this request query include:

FieldData TypeDescription
currencyStringOptional - transaction currency e.g. NGN, KES, GHS, ZAR, etc.
date_fromStringOptional - fetch transactions from this date. Use format YYYY-MM-DD-HH-MM-SS.
date_toStringOptional - fetch transactions up to this date. Use format YYYY-MM-DD-HH-MM-SS.
limitNumberOptional - If not passed, we send a limit of 10.
starting_afterStringOptional - used for pagination, must be used separately with ending_before, it expects the pointer from the response.
ending_beforeStringOptional - used for pagination, must be used separately with starting_after, it expects the pointer from the response.

Here's an example of how the response could look like:

{
  "has_more": true,
  "data": {
    "pointer": "cus_16FC",
    "reference": "555780645",
    "status": "success",
    "amount": "1500.00",
    "fee": "40.31",
    "currency": "NGN",
    "narration": "Transfer from Young and free",
    "trace_id": "14530184957",
    "message": "Payout successful",
    "customer_name": "John Doe",
    "customer_email": "[email protected]",
    "date_created": "2023-09-07 07:16:04",
    "date_completed": "2023-09-07 07:18:17"
  }
}

Receive confirmation via webhook

You can set your application to receive a confirmation via webhooks when the payout is completed. Please visit Webhooks to see more information about the webhook request body and how to verify and handle the webhook request.