Initiate Payout
curl --request POST \
--url https://dev.waftpay.io/payments/v1/payouts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Custom-Signature: <x-custom-signature>' \
--data '
{
"transaction": {
"reference": "TXN213687756272200",
"amount": 1000,
"currency": "KES",
"description": "Test description",
"service_code": "MPESAB2C",
"timestamp": "2025-01-21T12:30:10Z"
},
"originator": {
"msisdn": "254708374149",
"channel": "USSD",
"country": "KE",
"name": "John Doe",
"purpose": "Salary Payment"
},
"recipient": {
"reference": "INVJMA02",
"account": "254708374149",
"name": "John Doe Init",
"destination_code": "300213"
},
"callback_url": "https://merchant.example.com/callbacks/payout",
"meta": {}
}
'import requests
url = "https://dev.waftpay.io/payments/v1/payouts"
payload = {
"transaction": {
"reference": "TXN213687756272200",
"amount": 1000,
"currency": "KES",
"description": "Test description",
"service_code": "MPESAB2C",
"timestamp": "2025-01-21T12:30:10Z"
},
"originator": {
"msisdn": "254708374149",
"channel": "USSD",
"country": "KE",
"name": "John Doe",
"purpose": "Salary Payment"
},
"recipient": {
"reference": "INVJMA02",
"account": "254708374149",
"name": "John Doe Init",
"destination_code": "300213"
},
"callback_url": "https://merchant.example.com/callbacks/payout",
"meta": {}
}
headers = {
"X-Custom-Signature": "<x-custom-signature>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Custom-Signature': '<x-custom-signature>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
transaction: {
reference: 'TXN213687756272200',
amount: 1000,
currency: 'KES',
description: 'Test description',
service_code: 'MPESAB2C',
timestamp: '2025-01-21T12:30:10Z'
},
originator: {
msisdn: '254708374149',
channel: 'USSD',
country: 'KE',
name: 'John Doe',
purpose: 'Salary Payment'
},
recipient: {
reference: 'INVJMA02',
account: '254708374149',
name: 'John Doe Init',
destination_code: '300213'
},
callback_url: 'https://merchant.example.com/callbacks/payout',
meta: {}
})
};
fetch('https://dev.waftpay.io/payments/v1/payouts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://dev.waftpay.io/payments/v1/payouts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'transaction' => [
'reference' => 'TXN213687756272200',
'amount' => 1000,
'currency' => 'KES',
'description' => 'Test description',
'service_code' => 'MPESAB2C',
'timestamp' => '2025-01-21T12:30:10Z'
],
'originator' => [
'msisdn' => '254708374149',
'channel' => 'USSD',
'country' => 'KE',
'name' => 'John Doe',
'purpose' => 'Salary Payment'
],
'recipient' => [
'reference' => 'INVJMA02',
'account' => '254708374149',
'name' => 'John Doe Init',
'destination_code' => '300213'
],
'callback_url' => 'https://merchant.example.com/callbacks/payout',
'meta' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Custom-Signature: <x-custom-signature>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://dev.waftpay.io/payments/v1/payouts"
payload := strings.NewReader("{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Custom-Signature", "<x-custom-signature>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://dev.waftpay.io/payments/v1/payouts")
.header("X-Custom-Signature", "<x-custom-signature>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://dev.waftpay.io/payments/v1/payouts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Custom-Signature"] = '<x-custom-signature>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}"
response = http.request(request)
puts response.read_body{
"status": "<string>",
"code": "<string>",
"description": "<string>",
"data": {
"amount": 123,
"transaction_reference": "<string>",
"payment_uuid": "<string>",
"payment_reference": "<string>",
"time_received": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}{
"code": "400.001.100",
"status": "REJECTED",
"description": "Invalid or expired token",
"data": {}
}Payouts
Initiate Payout
Send money to a customer using Waftpay Payouts API.
POST
/
payments
/
v1
/
payouts
Initiate Payout
curl --request POST \
--url https://dev.waftpay.io/payments/v1/payouts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Custom-Signature: <x-custom-signature>' \
--data '
{
"transaction": {
"reference": "TXN213687756272200",
"amount": 1000,
"currency": "KES",
"description": "Test description",
"service_code": "MPESAB2C",
"timestamp": "2025-01-21T12:30:10Z"
},
"originator": {
"msisdn": "254708374149",
"channel": "USSD",
"country": "KE",
"name": "John Doe",
"purpose": "Salary Payment"
},
"recipient": {
"reference": "INVJMA02",
"account": "254708374149",
"name": "John Doe Init",
"destination_code": "300213"
},
"callback_url": "https://merchant.example.com/callbacks/payout",
"meta": {}
}
'import requests
url = "https://dev.waftpay.io/payments/v1/payouts"
payload = {
"transaction": {
"reference": "TXN213687756272200",
"amount": 1000,
"currency": "KES",
"description": "Test description",
"service_code": "MPESAB2C",
"timestamp": "2025-01-21T12:30:10Z"
},
"originator": {
"msisdn": "254708374149",
"channel": "USSD",
"country": "KE",
"name": "John Doe",
"purpose": "Salary Payment"
},
"recipient": {
"reference": "INVJMA02",
"account": "254708374149",
"name": "John Doe Init",
"destination_code": "300213"
},
"callback_url": "https://merchant.example.com/callbacks/payout",
"meta": {}
}
headers = {
"X-Custom-Signature": "<x-custom-signature>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Custom-Signature': '<x-custom-signature>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
transaction: {
reference: 'TXN213687756272200',
amount: 1000,
currency: 'KES',
description: 'Test description',
service_code: 'MPESAB2C',
timestamp: '2025-01-21T12:30:10Z'
},
originator: {
msisdn: '254708374149',
channel: 'USSD',
country: 'KE',
name: 'John Doe',
purpose: 'Salary Payment'
},
recipient: {
reference: 'INVJMA02',
account: '254708374149',
name: 'John Doe Init',
destination_code: '300213'
},
callback_url: 'https://merchant.example.com/callbacks/payout',
meta: {}
})
};
fetch('https://dev.waftpay.io/payments/v1/payouts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://dev.waftpay.io/payments/v1/payouts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'transaction' => [
'reference' => 'TXN213687756272200',
'amount' => 1000,
'currency' => 'KES',
'description' => 'Test description',
'service_code' => 'MPESAB2C',
'timestamp' => '2025-01-21T12:30:10Z'
],
'originator' => [
'msisdn' => '254708374149',
'channel' => 'USSD',
'country' => 'KE',
'name' => 'John Doe',
'purpose' => 'Salary Payment'
],
'recipient' => [
'reference' => 'INVJMA02',
'account' => '254708374149',
'name' => 'John Doe Init',
'destination_code' => '300213'
],
'callback_url' => 'https://merchant.example.com/callbacks/payout',
'meta' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Custom-Signature: <x-custom-signature>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://dev.waftpay.io/payments/v1/payouts"
payload := strings.NewReader("{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Custom-Signature", "<x-custom-signature>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://dev.waftpay.io/payments/v1/payouts")
.header("X-Custom-Signature", "<x-custom-signature>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://dev.waftpay.io/payments/v1/payouts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Custom-Signature"] = '<x-custom-signature>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"transaction\": {\n \"reference\": \"TXN213687756272200\",\n \"amount\": 1000,\n \"currency\": \"KES\",\n \"description\": \"Test description\",\n \"service_code\": \"MPESAB2C\",\n \"timestamp\": \"2025-01-21T12:30:10Z\"\n },\n \"originator\": {\n \"msisdn\": \"254708374149\",\n \"channel\": \"USSD\",\n \"country\": \"KE\",\n \"name\": \"John Doe\",\n \"purpose\": \"Salary Payment\"\n },\n \"recipient\": {\n \"reference\": \"INVJMA02\",\n \"account\": \"254708374149\",\n \"name\": \"John Doe Init\",\n \"destination_code\": \"300213\"\n },\n \"callback_url\": \"https://merchant.example.com/callbacks/payout\",\n \"meta\": {}\n}"
response = http.request(request)
puts response.read_body{
"status": "<string>",
"code": "<string>",
"description": "<string>",
"data": {
"amount": 123,
"transaction_reference": "<string>",
"payment_uuid": "<string>",
"payment_reference": "<string>",
"time_received": "2023-11-07T05:31:56Z"
}
}{
"error": "<string>",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}{
"code": "400.001.100",
"status": "REJECTED",
"description": "Invalid or expired token",
"data": {}
}Overview
Use the Payouts API to disburse funds from your Waftpay wallet to a customer, vendor, or partner. Payouts are asynchronous: you receive an acceptance response immediately, then a final outcome via webhook. This call is idempotent. Reuse the sametransaction.reference to safely retry the same logical payout.
Authentication and signature
Required headers| Header | Required | Notes |
|---|---|---|
Authorization | Yes | Bearer <payout_token> (payout product token only) |
X-Custom-Signature | Yes | Base64 RSA signature. See Signature generation. |
Content-Type | Yes | application/json |
Request body
Top-level fields| Field | Type | Required | Notes |
|---|---|---|---|
transaction | object | Yes | Payout details and idempotency reference. |
originator | object | Yes | Sender details. |
recipient | object | Yes | Recipient details. |
callback_url | string | Yes | HTTPS URL for final status callbacks. |
meta | object | No | Arbitrary key/value metadata echoed in callbacks. |
| Field | Type | Required | Notes |
|---|---|---|---|
reference | string | Yes | Client-generated unique reference (idempotency key). |
amount | integer | Yes | Amount in major units (e.g., 1000 = 1000 KES). |
currency | string | Yes | ISO 4217 currency code (e.g., KES, USD). |
description | string | Yes | Short narrative for the payout. |
service_code | string | Yes | Service to use (e.g., MPESAB2C). |
timestamp | string | Yes | ISO 8601 UTC timestamp (must end with Z). |
| Field | Type | Required | Notes |
|---|---|---|---|
msisdn | string | Yes | MSISDN format (e.g., 2547XXXXXXXX). |
channel | string | Yes | Initiation channel (e.g., USSD, API). |
country | string | Yes | ISO 3166-1 country code (e.g., KE). |
name | string | Yes | Originator name. |
purpose | string | Yes | Reason for the payout. |
| Field | Type | Required | Notes |
|---|---|---|---|
reference | string | Yes | Client-generated reference for recipient-side tracking. |
account | string | Yes | Recipient account identifier (phone, wallet, bank account). |
name | string | Yes | Recipient full name. |
destination_code | string | Yes | Destination code for the recipient corridor or payout rail. |
Example request
{
"transaction": {
"reference": "TXN213687756272200",
"amount": 1000,
"currency": "KES",
"description": "Vendor payout",
"service_code": "MPESAB2C",
"timestamp": "2025-01-21T12:30:10Z"
},
"originator": {
"msisdn": "254708374149",
"channel": "USSD",
"country": "KE",
"name": "Payment",
"purpose": "Transaction Payment"
},
"recipient": {
"reference": "INVJMA02",
"account": "254708374149",
"name": "John Doe Init",
"destination_code": "300213"
},
"callback_url": "https://merchant.example.com/callbacks/payout",
"meta": {
"note": "This info is returned as part of the callback",
"agent_id": "AGENT458"
}
}
Example response (accepted)
{
"code": "100",
"status": "ACCEPTED",
"description": "Accepted for processing",
"data": {
"amount": 100,
"transaction_reference": "919938",
"payment_uuid": "413283551143664292",
"payment_reference": "351CSICLV0",
"time_received": "2026-01-07T09:44:43.558023Z"
}
}
Notes
- Final outcome is delivered via webhook. See Webhooks overview.
- Errors follow the standard error shape. See Errors.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Base64 RSA signature over: transaction.reference + transaction.amount + originator.country + transaction.service_code
Body
application/json
