Payouts API
Send payments to till/paybill numbers and mobile money wallets across Africa.
Mobile Money Transfer
Initiate a payout to a mobile money wallet.
POST /business/payout/transferMobile Money Request Body
| Field | Type | Required | Description |
|---|---|---|---|
senderCurrency | string | Yes | Sender’s currency code (USD, EUR, etc.) |
receiverCurrency | string | Yes | Receiver’s currency code (KES, TZS, UGX, ZAR) |
amount | number | Yes | Amount to send in receiver’s currency |
senderFirstName | string | Yes | Sender’s first name |
senderLastName | string | Yes | Sender’s last name |
senderDob | string | Yes | Sender’s date of birth (YYYY-MM-DD) |
senderIdType | string | Yes | ID type: passport, national_id, driving_license |
senderIdNumber | string | Yes | Sender’s ID number |
senderNationality | string | Yes | Sender’s nationality (2-letter country code) |
senderTelephoneNo | string | Yes | Sender’s phone number with country code |
receiverFirstName | string | Yes | Receiver’s first name |
receiverLastName | string | Yes | Receiver’s last name |
receiverPhone | string | Yes | Receiver’s phone number with country code |
relationship | string | Yes | Relationship to receiver (e.g., “Family”, “Business”) |
payoutCountry | string | Yes | Destination country code (KE, TZ, UG, ZA) |
purposeOfTransfer | string | Yes | Purpose (see allowed values below) |
sourceOfFunds | string | Yes | Source of funds (see allowed values below) |
businessReference | string | Yes | Your unique transaction reference |
callbackUrl | string | No | Absolute callback URL for this payout’s final status |
forceStatus | string | Test only | Force a TESTENV outcome (see Test Payout Outcomes) |
Example Request - Kenya Mobile Money
curl -X POST https://api.test.wakapay.io/business/payout/transfer \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"senderCurrency": "USD",
"receiverCurrency": "KES",
"amount": 100.0,
"senderFirstName": "Alice",
"senderLastName": "Smith",
"senderDob": "1985-03-15",
"senderIdType": "passport",
"senderIdNumber": "AB1234567",
"senderNationality": "TZ",
"senderTelephoneNo": "+255712345678",
"receiverFirstName": "John",
"receiverLastName": "Doe",
"receiverPhone": "+254700000001",
"relationship": "Family",
"payoutCountry": "KE",
"purposeOfTransfer": "family_support",
"sourceOfFunds": "salary",
"businessReference": "TEST-TRANSFER-KE-001",
"callbackUrl": "https://partner.example.com/webhooks/wakapay/TEST-TRANSFER-KE-001"
}'const response = await fetch(
"https://api.test.wakapay.io/business/payout/transfer",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
senderCurrency: "USD",
receiverCurrency: "KES",
amount: 100.0,
senderFirstName: "Alice",
senderLastName: "Smith",
senderDob: "1985-03-15",
senderIdType: "passport",
senderIdNumber: "AB1234567",
senderNationality: "TZ",
senderTelephoneNo: "+255712345678",
receiverFirstName: "John",
receiverLastName: "Doe",
receiverPhone: "+254700000001",
relationship: "Family",
payoutCountry: "KE",
purposeOfTransfer: "family_support",
sourceOfFunds: "salary",
businessReference: "TEST-TRANSFER-KE-001",
callbackUrl:
"https://partner.example.com/webhooks/wakapay/TEST-TRANSFER-KE-001",
}),
},
)
const data = await response.json()
console.log(data)Mobile Money Response (201 Created)
{
"businessReference": "TEST-TRANSFER-KE-001",
"receiverAmount": 100,
"receiverCurrency": "KES",
"senderAmount": 0.7751937984496124,
"senderCurrency": "USD",
"status": "termination_pending",
"totalDebited": 0.7906976744186047,
"wakapayReference": "0ad0a4a6-364b-11f1-8c14-0242ac120008"
}Response Fields
| Field | Type | Description |
|---|---|---|
wakapayReference | string | Wakapay transaction ID |
businessReference | string | Your reference for tracking |
status | string | Transaction status (termination_success, termination_pending, termination_failure) |
senderAmount | number | Amount debited from sender wallet |
senderCurrency | string | Sender’s currency |
receiverAmount | number | Amount received by recipient |
receiverCurrency | string | Receiver’s currency |
totalDebited | number | Total amount debited (includes fees) |
Per-request Callback URL
Use the optional callbackUrl field to receive the final status webhook at a URL selected for one payout. The value must be an absolute http:// or https:// URL. Use HTTPS in production.
Wakapay resolves the callback destination in this order:
- If the payout request includes
callbackUrl, Wakapay uses it for that payout only. - Otherwise, Wakapay uses the business account’s saved default callback URL.
- If neither URL is set, no webhook is sent. Poll
GET /business/transactions/{businessReference}for the final status.
The webhook payload and signature do not change. Only the destination URL changes. Wakapay sends the callback when the payout reaches termination_success or termination_failure.
To use the account default, omit the field:
{
"businessReference": "PAY-2026-00043"
}Payment to Paybill / Till
Initiate a payment to a Paybill or Till number.
POST /business/payout/paymentDifference between Till and Paybill:
- Till (Lipa Number) - No account reference needed. Payment goes directly to the till number.
- Paybill - Requires an account reference (
receiverAccount). Payment goes to the paybill number with a specific account reference for tracking.
Till/Paybill Request Body
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Payment type: paybill or till |
senderCurrency | string | Yes | Sender’s currency code (USD, EUR, etc.) |
receiverCurrency | string | Yes | Receiver’s currency code (KES, TZS, UGX, ZAR) |
amount | number | Yes | Amount to send in receiver’s currency |
senderFirstName | string | Yes | Sender’s first name |
senderLastName | string | Yes | Sender’s last name |
senderDob | string | Yes | Sender’s date of birth (YYYY-MM-DD) |
senderIdType | string | Yes | ID type: passport, national_id, driving_license |
senderIdNumber | string | Yes | Sender’s ID number |
senderNationality | string | Yes | Sender’s nationality (2-letter country code) |
senderTelephoneNo | string | Yes | Sender’s phone number with country code |
receiverFirstName | string | Yes | Receiver’s first name |
receiverLastName | string | Yes | Receiver’s last name |
receiverLipaNumber | string | Yes | Paybill or Till number |
receiverAccount | string | Conditional | Paybill account/reference (required for paybill, omit for till) |
relationship | string | Yes | Relationship to receiver (e.g., “Family”, “Business”) |
payoutCountry | string | Yes | Destination country code (KE, TZ, UG, ZA) |
purposeOfTransfer | string | Yes | Purpose (see allowed values below) |
sourceOfFunds | string | Yes | Source of funds (see allowed values below) |
businessReference | string | Yes | Your unique transaction reference |
callbackUrl | string | No | Absolute callback URL for this payout’s final status |
forceStatus | string | Test only | Force a TESTENV outcome (see Test Payout Outcomes) |
Example Request - Till Payment
curl -X POST https://api.test.wakapay.io/business/payout/payment \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "till",
"senderCurrency": "USD",
"receiverCurrency": "KES",
"amount": 100.0,
"senderFirstName": "Alice",
"senderLastName": "Smith",
"senderDob": "1985-03-15",
"senderIdType": "passport",
"senderIdNumber": "AB1234567",
"senderNationality": "TZ",
"senderTelephoneNo": "+255712345678",
"receiverFirstName": "John",
"receiverLastName": "Doe",
"receiverLipaNumber": "888880",
"relationship": "Family",
"payoutCountry": "KE",
"purposeOfTransfer": "family_support",
"sourceOfFunds": "salary",
"businessReference": "TEST-PAYMENT-KE-TILL-001"
}'const response = await fetch(
"https://api.test.wakapay.io/business/payout/payment",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "till",
senderCurrency: "USD",
receiverCurrency: "KES",
amount: 100.0,
senderFirstName: "Alice",
senderLastName: "Smith",
senderDob: "1985-03-15",
senderIdType: "passport",
senderIdNumber: "AB1234567",
senderNationality: "TZ",
senderTelephoneNo: "+255712345678",
receiverFirstName: "John",
receiverLastName: "Doe",
receiverLipaNumber: "888880",
relationship: "Family",
payoutCountry: "KE",
purposeOfTransfer: "family_support",
sourceOfFunds: "salary",
businessReference: "TEST-PAYMENT-KE-TILL-001",
}),
},
)
const data = await response.json()
console.log(data)Till Response (201 Created)
{
"businessReference": "TEST-PAYMENT-KE-TILL-001",
"receiverAmount": 100,
"receiverCurrency": "KES",
"senderAmount": 0.7751937984496124,
"senderCurrency": "USD",
"status": "termination_pending",
"totalDebited": 0.7906976744186047,
"wakapayReference": "3454311f-364b-11f1-8c14-0242ac120008"
}Example Request - Paybill Payment
curl -X POST https://api.test.wakapay.io/business/payout/payment \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "paybill",
"senderCurrency": "USD",
"receiverCurrency": "KES",
"amount": 100.0,
"senderFirstName": "Alice",
"senderLastName": "Smith",
"senderDob": "1985-03-15",
"senderIdType": "passport",
"senderIdNumber": "AB1234567",
"senderNationality": "TZ",
"senderTelephoneNo": "+255712345678",
"receiverFirstName": "John",
"receiverLastName": "Doe",
"receiverLipaNumber": "123456",
"receiverAccount": "ABC123",
"relationship": "Family",
"payoutCountry": "KE",
"purposeOfTransfer": "family_support",
"sourceOfFunds": "salary",
"businessReference": "TEST-PAYMENT-KE-PAYBILL-001"
}'Response - Paybill (201 Created)
{
"businessReference": "TEST-PAYMENT-KE-PAYBILL-001",
"receiverAmount": 100,
"receiverCurrency": "KES",
"senderAmount": 0.7751937984496124,
"senderCurrency": "USD",
"status": "termination_pending",
"totalDebited": 0.7906976744186047,
"wakapayReference": "3487eae9-364b-11f1-8c14-0242ac120008"
}Uganda Till (MTN MoMo Pay) Payouts
Pay Ugandan merchant tills through MTN MoMo Pay. Uganda supports type: "till" only; paybill payments are not supported.
TESTENV UAT Till
| Field | Value |
|---|---|
| Till | 800001 |
| Name | Kampala Spices |
1. Decode the QR Code (Optional)
Decode the merchant QR string to retrieve its till number.
POST /business/decode-qr{
"qrString": "800001@momopay:undefined:undefined:256700000001:Kampala Spices",
"country": "UG"
}You may omit the country hint. When provided, either country or countryCode can be used.
Decode Response
{
"countryCode": "UG",
"currency": "UGX",
"merchantName": "Kampala Spices",
"channel": "MTN",
"tillNumber": "800001",
"merchantMobile": "+256700000001",
"amount": null
}Use the returned tillNumber as lipaNumber when verifying the till and as receiverLipaNumber when creating the payout.
2. Verify the Till
POST /business/verify-payment{
"countryCode": "UG",
"type": "till",
"lipaNumber": "800001"
}Verification Response
{
"verified": true,
"displayName": "Kampala Spices"
}3. Create the Payout
POST /business/payout/payment{
"type": "till",
"receiverLipaNumber": "800001",
"amount": 1000,
"senderCurrency": "USD",
"receiverCurrency": "UGX",
"payoutCountry": "UG",
"businessReference": "UG-TILL-001",
"purposeOfTransfer": "business_payment",
"sourceOfFunds": "business_income",
"senderFirstName": "Acme",
"senderLastName": "Ltd",
"senderDob": "1990-01-15",
"senderIdType": "passport",
"senderIdNumber": "P1234567",
"senderNationality": "TZ",
"senderTelephoneNo": "+255712345678",
"receiverFirstName": "Kampala",
"receiverLastName": "Spices"
}Uganda Till Rules
| Rule | Detail |
|---|---|
| Minimum amount | 500 UGX |
type | Must be "till" |
receiverCurrency | Must be "UGX" |
payoutCountry | Must be "UG" |
| Receiver names | Optional. If omitted, the API validates the till with Xente and fills in the merchant name. |
Bank Payouts
Get Banks
Retrieve the supported banks for a payout country. Use the returned bank code as receiverBankCode when creating a bank payout.
GET /business/banks?countryCode={countryCode}| Query parameter | Type | Required | Description |
|---|---|---|---|
countryCode | string | Yes | Bank country code. Use KE or ZA |
curl "https://api.test.wakapay.io/business/banks?countryCode=KE" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/json"Create a Bank Payout
POST /business/payout/bank| Field | Type | Required | Description |
|---|---|---|---|
senderCurrency | string | Yes | Sender’s currency code |
receiverCurrency | string | Yes | KES for Kenya or ZAR for South Africa |
amount | number | Yes | Amount to send in receiver’s currency |
payoutCountry | string | Yes | KE or ZA |
businessReference | string | Yes | Your unique transaction reference |
senderTelephoneNo | string | Yes | Sender’s phone number with country code |
senderFirstName | string | Yes | Sender’s first name |
senderLastName | string | Yes | Sender’s last name |
senderDob | string | Yes | Sender’s date of birth (YYYY-MM-DD) |
senderIdType | string | Yes | passport, national_id, or driving_license |
senderIdNumber | string | Yes | Sender’s identity document number |
senderNationality | string | Yes | Sender’s two-letter nationality code |
receiverFirstName | string | Yes | Receiver’s first name |
receiverLastName | string | Yes | Receiver’s last name |
receiverBankCode | string | Yes | Bank code returned by the banks endpoint |
receiverAccountNumber | string | Yes | Receiver’s bank account number |
receiverEmail | string | Conditional | Required for South African (ZA) bank payouts |
relationship | string | Yes | Sender’s relationship to the receiver |
purposeOfTransfer | string | Yes | Purpose of transfer |
sourceOfFunds | string | Yes | Source of funds |
callbackUrl | string | No | Absolute callback URL for this payout’s final status |
Kenya Bank Payout
curl -X POST https://api.test.wakapay.io/business/payout/bank \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"senderCurrency": "USD",
"receiverCurrency": "KES",
"amount": 5000,
"payoutCountry": "KE",
"businessReference": "PAY-KE-2026-00001",
"senderTelephoneNo": "+255712345678",
"senderFirstName": "Nate",
"senderLastName": "Smith",
"senderDob": "1990-01-01",
"senderIdType": "passport",
"senderIdNumber": "AB1234567",
"senderNationality": "TZ",
"receiverFirstName": "Jane",
"receiverLastName": "Wanjiku",
"receiverBankCode": "320",
"receiverAccountNumber": "1234567890",
"relationship": "Business",
"purposeOfTransfer": "business_payment",
"sourceOfFunds": "business_income",
"callbackUrl": "https://partner.example.com/webhooks/wakapay/PAY-KE-2026-00001"
}'{
"wakapayReference": "c3d4e5f6-a7b8-9012-cdef-123456789012",
"businessReference": "PAY-KE-2026-00001",
"status": "termination_pending",
"senderCurrency": "USD",
"receiverCurrency": "KES",
"senderAmount": 38.46,
"receiverAmount": 5000,
"totalDebited": 40.46
}South Africa Bank Payout
South African bank payouts require receiverEmail.
curl -X POST https://api.test.wakapay.io/business/payout/bank \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"senderCurrency": "USD",
"receiverCurrency": "ZAR",
"amount": 2000,
"payoutCountry": "ZA",
"businessReference": "PAY-ZA-2026-00001",
"senderTelephoneNo": "+255712345678",
"senderFirstName": "Nate",
"senderLastName": "Smith",
"senderDob": "1990-01-01",
"senderIdType": "passport",
"senderIdNumber": "AB1234567",
"senderNationality": "TZ",
"receiverFirstName": "John",
"receiverLastName": "Smith",
"receiverBankCode": "940044",
"receiverAccountNumber": "9876543210",
"receiverEmail": "uat.receiver@example.com",
"relationship": "Business",
"purposeOfTransfer": "business_payment",
"sourceOfFunds": "business_income",
"callbackUrl": "https://partner.example.com/webhooks/wakapay/PAY-ZA-2026-00001"
}'{
"wakapayReference": "d4e5f6a7-b8c9-0123-def0-234567890123",
"businessReference": "PAY-ZA-2026-00001",
"status": "termination_pending",
"senderCurrency": "USD",
"receiverCurrency": "ZAR",
"senderAmount": 120.48,
"receiverAmount": 2000,
"totalDebited": 122.48
}Transaction Status Values
| Status | Description |
|---|---|
termination_pending | Transaction initiated, awaiting completion |
termination_success | Transaction completed successfully |
termination_failure | Transaction failed |
Test Payout Outcomes
Use forceStatus on POST /business/payout/transfer or POST /business/payout/payment to test specific outcomes.
| Value | Behavior |
|---|---|
termination_failure | Returns a pending payout, then sends a termination_failure webhook |
insufficient_balance | Returns 412 immediately and does not create a payout |
termination_success | Returns a pending payout, then sends a termination_success webhook |
Omitting forceStatus follows the normal TESTENV success flow. Use a unique businessReference for every test.
curl -X POST https://api.test.wakapay.io/business/payout/transfer \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"forceStatus": "termination_failure",
"senderCurrency": "USD",
"receiverCurrency": "KES",
"amount": 1000,
"senderFirstName": "Test",
"senderLastName": "Sender",
"senderDob": "1990-01-01",
"senderIdType": "passport",
"senderIdNumber": "TEST123456",
"senderNationality": "US",
"senderTelephoneNo": "+12025550100",
"receiverFirstName": "Amina",
"receiverLastName": "Mjema",
"receiverPhone": "+254700000001",
"relationship": "Business",
"payoutCountry": "KE",
"purposeOfTransfer": "family_support",
"sourceOfFunds": "salary",
"businessReference": "TEST-FAIL-2026-0001",
"callbackUrl": "https://partner.example.com/webhooks/wakapay/TEST-FAIL-2026-0001"
}'Purpose of Transfer - Allowed Values
All valid values for the purposeOfTransfer field:
family_support- Family support and remittanceseducation- Educational expensesbusiness_payment- Business-related paymentsmedical- Medical expensesinvestment- Investment purposesconstruction- Construction expensesrent- Rent and housinggeneral- General purposesfuel- Fuel and energyrepairs- Repairs and maintenancegift- Giftspersonal_care- Personal care expensesfood_and_groceries- Food and groceriestransport- Transportationtravel- Travel expensesshopping- Shoppingentertainment- Entertainmentdonations- Charitable donationsother- Other purposes
Source of Funds - Allowed Values
All valid values for the sourceOfFunds field:
salary- Employment salarysavings- Personal savingsbusiness_income- Business incomesale_of_assets- Sale of assetsinvestment_income- Investment returnsother- Other sources
TESTENV Test Credentials
Test Phone Numbers (Mobile Money)
| Country | Phone Number | Status | Display Name |
|---|---|---|---|
| Kenya (KE) | +254700000001 | Verified, payout success | Amina Mjema |
| Tanzania (TZ) | +255700000001 | Verified, no FX rate configured | Amina Mjema |
| Uganda (UG) | +256700000001 | Verified test recipient | Amina Mjema |
Test Lipa Numbers (Till/Paybill)
| Country | Type | Number | Account Ref | Status |
|---|---|---|---|---|
| Kenya (KE) | Till | 888880 | - | Verified, payout success |
| Kenya (KE) | Paybill | 123456 | ABC123 | Verified, payout success |
| Tanzania (TZ) | Till | 600000 | - | Verified, no FX rate |
| Tanzania (TZ) | Paybill | 700000 | ABC123 | Verified, no FX rate |
Test Bank Accounts
| Country | Bank code | Account | Account name | |
|---|---|---|---|---|
| Kenya (KE) | 320 | 1234567890 | Not required | Jane Wanjiku |
| South Africa (ZA) | 940044 | 9876543210 | Any valid email, such as uat.receiver@example.com | John Smith |
Note: Only USD→KES FX rate is configured in TESTENV. TZS payouts will fail with “rate USD_TZS not configured” error.
Error Responses
400 - Invalid Callback URL
{
"code": 0,
"error": "callbackUrl must be a valid absolute URL"
}400 - Missing Required Field
{
"code": 0,
"error": "receiverPhone is required"
}{
"code": 0,
"error": "receiverLipaNumber is required"
}400 - Invalid purposeOfTransfer
{
"code": 0,
"error": "purposeOfTransfer must be one of: [family_support, education, business_payment, medical, investment, construction, rent, general, fuel, repairs, gift, personal_care, food_and_groceries, transport, travel, shopping, entertainment, donations, other]"
}400 - Invalid sourceOfFunds
{
"code": 0,
"error": "sourceOfFunds must be one of: [salary, savings, business_income, sale_of_assets, investment_income, other]"
}404 - FX Rate Not Configured
{
"code": 0,
"error": "rate USD_TZS not configured"
}409 - Duplicate Reference
{
"code": 0,
"error": "duplicate reference"
}412 - Insufficient Balance
{
"code": 0,
"error": "insufficient available balance"
}In TESTENV, set forceStatus to insufficient_balance to receive this response without creating a payout.
422 - Account Not Active
{
"code": 0,
"error": "account not active"
}Note: Non-test phone numbers in TESTENV will return this error.
Use Cases
Send Mobile Money Transfer
async function sendMobileMoneyTransfer(phone, amount, currency, countryCode) {
// Step 1: Verify recipient
const verifyResponse = await fetch(
"https://api.test.wakapay.io/business/verify-transfer",
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
countryCode: countryCode,
phoneNumber: phone,
}),
},
)
const verifyData = await verifyResponse.json()
if (!verifyData.verified) {
throw new Error("Recipient not verified")
}
console.log(`Sending to: ${verifyData.displayName}`)
// Step 2: Check FX rate
const rateResponse = await fetch(
`https://api.test.wakapay.io/business/rate?from=USD&to=${currency}`,
{
headers: { Authorization: `Bearer ${token}` },
},
)
const rateData = await rateResponse.json()
console.log(`FX Rate: ${rateData.rate}`)
// Step 3: Send transfer
const transferResponse = await fetch(
"https://api.test.wakapay.io/business/payout/transfer",
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
senderCurrency: "USD",
receiverCurrency: currency,
amount: amount,
senderFirstName: "Alice",
senderLastName: "Smith",
senderDob: "1985-03-15",
senderIdType: "passport",
senderIdNumber: "AB1234567",
senderNationality: "TZ",
senderTelephoneNo: "+255712345678",
receiverFirstName: verifyData.displayName.split(" ")[0],
receiverLastName: verifyData.displayName.split(" ")[1] || "User",
receiverPhone: phone,
relationship: "Family",
payoutCountry: countryCode,
purposeOfTransfer: "family_support",
sourceOfFunds: "salary",
businessReference: `TRF-${Date.now()}`,
}),
},
)
return await transferResponse.json()
}
// Usage
await sendMobileMoneyTransfer("+254700000001", 100, "KES", "KE")Send Till Payment
async function sendTillPayment(tillNumber, amount, currency, countryCode) {
// Step 1: Verify till number
const verifyResponse = await fetch(
"https://api.test.wakapay.io/business/verify-payment",
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
countryCode: countryCode,
type: "till",
lipaNumber: tillNumber,
}),
},
)
const verifyData = await verifyResponse.json()
if (!verifyData.verified) {
throw new Error("Till number not verified")
}
console.log(`Paying to: ${verifyData.displayName}`)
// Step 2: Send payment
const paymentResponse = await fetch(
"https://api.test.wakapay.io/business/payout/payment",
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "till",
senderCurrency: "USD",
receiverCurrency: currency,
amount: amount,
senderFirstName: "Alice",
senderLastName: "Smith",
senderDob: "1985-03-15",
senderIdType: "passport",
senderIdNumber: "AB1234567",
senderNationality: "TZ",
senderTelephoneNo: "+255712345678",
receiverFirstName: "Merchant",
receiverLastName: "Name",
receiverLipaNumber: tillNumber,
relationship: "Business",
payoutCountry: countryCode,
purposeOfTransfer: "business_payment",
sourceOfFunds: "business_income",
businessReference: `TILL-${Date.now()}`,
}),
},
)
return await paymentResponse.json()
}
// Usage
await sendTillPayment("888880", 100, "KES", "KE")Best Practices
- Always use unique references - Prevents duplicate payments (409 error)
- Verify recipients first - Use verify-transfer or verify-payment endpoints
- Check FX rates - Ensure currency pair is configured before cross-currency payouts
- Display verification results - Show displayName to user for confirmation
- Handle errors gracefully - Implement proper error handling for all error codes
- Use TESTENV numbers for testing - Use provided test credentials in test environment
- Include receiverAccount for paybill - Required field for paybill payments
Supported Countries
- KE - Kenya
- TZ - Tanzania
- UG - Uganda
- ZA - South Africa
Related
- Recipient Verification - Verify recipients before sending
- Transactions - Check payment status
- Error Handling - Handle payout errors