Skip to main content

Direct payments & payouts

Beyond the hosted checkout, the API exposes direct endpoints for collecting from and paying out to M-Pesa and banks. All of them require a company Bearer token, and all of them return a transaction you can poll at GET /v1/transactions/{id}.

Collections (money in)​

M-Pesa STK push​

POST /v1/transactions/m-pesa/c2b/initiate

Sends the payment prompt straight to the customer's phone:

curl -X POST https://sandbox.merchants.taifapay.africa/v1/transactions/m-pesa/c2b/initiate \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "0712345678",
"amount": 100,
"accountReference": "Account123",
"transactionDesc": "Top-up",
"externalId": "your-transaction-id"
}'

The customer enters their M-Pesa PIN on the prompt; the transaction completes (or fails/times out) shortly after. Use webhooks or poll the returned transaction id.

POST /v1/transactions/pesalink/c2b/initiate

Creates a pending bank transaction; it completes when the customer finishes the transfer from their own bank:

curl -X POST https://sandbox.merchants.taifapay.africa/v1/transactions/pesalink/c2b/initiate \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"accountReference": "Account123",
"transactionDesc": "Invoice settlement",
"externalId": "your-transaction-id"
}'

Payouts (money out)​

:::caution Float required Payouts are funded from your company float. Each initiate call checks and reserves amount + fee from your float balance first; if it is insufficient you get a 400 with the available and required amounts. Fees follow the standard M-Pesa tariff for the amount. :::

M-Pesa B2C (send to phone)​

POST /v1/transactions/m-pesa/b2c/initiate

{
"amount": 100,
"phoneNumber": "0712345678",
"accountReference": "Account123",
"transactionDesc": "Withdrawal",
"externalId": "your-transaction-id"
}

Pochi la Biashara​

POST /v1/transactions/m-pesa/pochi/initiate

{
"amount": 100,
"pochiNumber": "0712345678",
"accountReference": "Account123",
"transactionDesc": "Payment to pochi"
}

Till (Buy Goods)​

POST /v1/transactions/m-pesa/till/initiate

{
"amount": 100,
"tillNumber": "123456",
"accountReference": "Account123",
"transactionDesc": "Payment to till",
"initiatorPhoneNumber": "0712345678"
}

Paybill​

POST /v1/transactions/m-pesa/paybill/initiate

{
"amount": 100,
"paybillNumber": "123456",
"accountNumber": "5551234",
"accountReference": "Account123",
"transactionDesc": "Payment to paybill",
"customerNumber": "0712345678"
}

Pays out to any PesaLink-connected bank account. Unlike the M-Pesa payouts, this is a two-step flow so you can show the resolved account holder name to your user before any money moves.

:::info Path prefix These two endpoints live under /v1/pesalink, not /v1/transactions. :::

Step 1 — verify the beneficiary and prepare the transfer. This verifies the destination account with the receiving bank, reserves your float for amount + fee, and returns a transactionId for a pending transfer:

curl -X POST https://sandbox.merchants.taifapay.africa/v1/pesalink/bank-transfer/verify \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"destinationBankCode": "40407000",
"destinationAccount": "7357060021",
"amount": 5000,
"narrative": "Supplier payment",
"reference": "INV-2024-001"
}'
{
"transactionId": "WDRPSLK1A2B3C4D5E6F7A8B9",
"accountHolderName": "John ****",
"amount": 5000,
"fee": 22,
"currency": "KES",
"beneficiaryAccount": "7357060021",
"beneficiaryBankCode": "40407000",
"status": "pending",
"message": "Beneficiary verified and transfer prepared. Confirm with the transactionId to complete."
}

If verification fails or your float is insufficient, this returns 400 and no transfer is created.

Step 2 — complete the transfer using the transactionId from step 1. On success the amount + fee is drawn down from your float:

curl -X POST https://sandbox.merchants.taifapay.africa/v1/pesalink/bank-transfer/complete \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "transactionId": "WDRPSLK1A2B3C4D5E6F7A8B9" }'
{
"message": "Bank transfer completed successfully",
"transaction": { /* transaction object, type BANK_TRANSFER */ }
}

404 if the transactionId isn't a pending transfer for your merchant; 422 if it's already settled or the receiving bank rejects it.

See the PesaLink bank codes table below for the destinationBankCode values.

Tracking transactions​

Every initiate endpoint responds with a transaction object. Fetch its latest state at any time:

curl https://sandbox.merchants.taifapay.africa/v1/transactions/{id} \
-H "Authorization: Bearer $ACCESS_TOKEN"

You can pass either the API's transaction id or your own externalId reference. Statuses move pending → complete or failed; payouts release their float reservation if they fail.

Idempotency and reconciliation​

  • Always set externalId to your own unique id for the operation. It is echoed back on transactions and webhooks, letting you match events to your records.
  • If an initiate call times out on your side, do not blindly retry — first look the transaction up by your externalId to see whether it was created.

Use the code as destinationBankCode when preparing a PesaLink bank transfer. The Live column reflects PesaLink availability at the time of writing — banks marked No or ON PILOT may reject transfers.

BankCodeLive
ABC Bank40435000Yes
ABSA40403000Yes
Access Bank40426000Yes
Bank of Africa40419000Yes
Bank of Baroda40406000Yes
Bank of India40405000No
Caritas Microfinance Bank40448000Yes
Choice Microfinance Bank40436000Yes
CIB Bank Kenya40465000Yes
Citi Bank40416000Yes
Consolidated Bank40423000Yes
Cooperative Bank40411000Yes
Credit Bank40425000Yes
Development Bank40459000ON PILOT
DIB Bank40475000Yes
DTB40463000Yes
Eco Bank40443000Yes
Equity Bank40468000Yes
Family Bank40470000Yes
Faulu Bank40479000Yes
Gt Bank40453000Yes
Guardian Bank40455000Yes
Gulf African Bank40472000Yes
Habib Bank AG Zurich40417000Yes
Housing Finance40461000Yes
I&M Bank40457000Yes
KCB Bank40401000Yes
Kingdom Bank40451000Yes
KWFT40478000Yes
LOOP-NCBA40401380Yes
M-Oriental40414000Yes
Middle East Bank40418000Yes
National Bank40412000Yes
NCBA40407000Yes
Paramount40450000Yes
Post Bank40462000Yes
Premier Bank40474000Yes
Prime Bank40410000Yes
SBM40460000Yes
Sidian Bank40466000Yes
Stanbic Bank40431000Yes
Standard Chartered Bank40402000Yes
Stima SACCO40489000Yes
Telkom Kenya40497000Yes
UBA Bank40476000Yes
UMBA Microfinance Bank40467000Yes
Unaitas Sacco40432000Yes
Victoria Bank40454000Yes
VOOMA40493000Yes