DEV Community

Sospeter Mong'are
Sospeter Mong'are

Posted on

KCB Funds Transfer API

The KCB Funds Transfer API enables businesses and applications to securely initiate funds transfers programmatically without requiring manual intervention through the KCB banking platform (Mobile app and Web). This guide walks you through the API, request parameters, authentication, transaction flow, and how to successfully integrate and test a funds transfer.


What Is the KCB Funds Transfer API?

Banks have always let you move money through their apps or teller counters. The KCB Funds Transfer (FT) API lets you do that same thing from your own application - by writing code.

Instead of a human clicking "Send Money" in the KCB app, your system sends an HTTP request to KCB's servers, and the money moves. That's it at the core.

This is useful when you're building:

  • A business payment system (e.g. auto-paying suppliers)
  • A SaaS platform that needs to disburse funds to users
  • A financial dashboard that triggers bank transfers
  • Any system where money movement needs to be automated

What Can It Actually Do?

The KCB FT API supports four types of money movement:

Transfer Type What It Means Code
Internal Transfer Between two KCB accounts IF
RTGS Large-value transfers to other banks RT
EFT Standard transfers to other banks EF
Pesalink Bank-to-bank transfers within Kenya's IPS PL
Mobile Money From KCB account to M-PESA wallet MO

You pick the type that fits your use case and pass the right code in your request.


Before You Write Any Code

There are two environments: Sandbox (for testing) and Production (real money). Always start with Sandbox.

To Get Started on Sandbox

  1. Register on the KCB Buni developer portal: sandbox.buni.kcbgroup.com
  2. Create an application on the portal
  3. Subscribe to the FT API - you'll get a Consumer Key and a Consumer Secret
  4. Have a Callback URL ready (more on this below)
  5. KCB will whitelist your Buni username and provide test account numbers

GOING LIVE (For Production (Real Money))

You'll additionally need:


How the API Works - The Big Picture

The KCB FT API is asynchronous. This is the most important thing to understand as a beginner.

When you send a transfer request, you don't get back "success" or "failed" immediately. Instead:

  1. You send the transfer request → KCB immediately replies: "Got it, we're processing"
  2. KCB processes the transfer in their core banking system
  3. KCB sends the result to your Callback URL via a POST request

This means your system needs to be able to receive incoming requests (a webhook endpoint), not just make outgoing ones. If you don't have a callback URL, you won't know whether transfers succeeded or failed.

Your App  ──POST──▶  KCB FT API  ──▶  Core Banking
                         │
                         └──POST──▶  Your Callback URL
                                      (result arrives here)
Enter fullscreen mode Exit fullscreen mode

Step 1: Get an Auth Token

Every API call to KCB requires a Bearer Token. You get this by calling the token endpoint using your Consumer Key and Consumer Secret from the Buni portal.

POST https://uat.buni.kcbgroup.com/token?grant_type=client_credentials
Authorization: Basic <base64(consumerKey:consumerSecret)>
Enter fullscreen mode Exit fullscreen mode

The response gives you an access token. Include it as a header in all subsequent requests:

Authorization: Bearer <your_token_here>
Enter fullscreen mode Exit fullscreen mode

Tokens expire, so your application should handle token refresh - request a new one when the old one stops working.


Step 2: Send a Transfer Request

Once you have a token, you can initiate a funds transfer. Here's what the request body looks like:

{
  "beneficiaryDetails": "John Doe",
  "companyCode": "KE0010001",
  "creditAccountNumber": "1234567890",
  "currency": "KES",
  "debitAccountNumber": "9876543210",
  "debitAmount": 5000,
  "paymentDetails": "Invoice #1042 settlement",
  "transactionReference": "MYAPP20240831001",
  "transactionType": "IF",
  "beneficiaryBankCode": "01"
}
Enter fullscreen mode Exit fullscreen mode

Let's break down each field:

Field What It Is Example
beneficiaryDetails Full name of who receives the money "John Doe"
companyCode KCB's internal code for your bank branch "KE0010001"
creditAccountNumber Account that receives the money "1234567890"
currency Always KES for Kenyan Shillings "KES"
debitAccountNumber Your KCB account (the one being charged) "9876543210"
debitAmount Amount to transfer (in KES) 5000
paymentDetails Short note about the transfer reason "Invoice settlement"
transactionReference Your unique ID for this transaction "MYAPP20240831001"
transactionType Type of transfer (see table above) "IF"
beneficiaryBankCode Bank code of the recipient's bank "01" for KCB

The transactionReference field is critical. It must be unique per transaction - never reuse it. This is how you and KCB track the same transaction. A good pattern: prefix + date + sequential number, e.g. PAY20240831001.


Step 3: Handle the Response

When your request reaches KCB, they send back an immediate acknowledgement. Here's what success looks like:

{
  "statusCode": "0",
  "statusMessage": "Success",
  "statusDescription": "Request received for processing",
  "merchantID": "263eb626-3fe7-4662-813e-f6f2962219e1",
  "retrievalRefNumber": "PCI663RSS"
}
Enter fullscreen mode Exit fullscreen mode

statusCode: "0" means KCB accepted your request. Save the merchantID - you can use it to reference this transaction later.

But this is not the final result. The transfer is still being processed.

Common Error Responses

Error What It Means Fix
Missing Credentials Token is missing or wrong Re-check your Bearer token
Validation failed: Invalid crucial param A field is missing or wrong value Review your request body
Retrieval RefNumber already exist You reused a transactionReference Generate a new unique reference
Transaction failed due to limit rule Amount exceeds your daily/transaction limit Adjust amount or check limits on FT portal

Step 4: Handle the Callback (The Real Result)

When KCB finishes processing, they POST to your Callback URL. This is what a successful notification looks like:

{
  "ftReference": "FT22060GXZGY",
  "transactionDate": "2022-07-06T11:08:40.019Z",
  "amount": "5000",
  "transactionStatus": "SUCCESS",
  "transactionMessage": "Processed Successfully",
  "beneficiaryAccountNumber": "1234567890",
  "beneficiaryName": "JOHN DOE",
  "transactionReference": "MYAPP20240831001",
  "merchantId": "1d2b13f8-ea62-465c-9fda-e18353579880",
  "debitAccountNumber": "9876543210"
}
Enter fullscreen mode Exit fullscreen mode

Your callback endpoint should:

  1. Check transactionStatus - it'll be SUCCESS or FAILED
  2. Match transactionReference to the transfer you initiated
  3. Update your database accordingly
  4. Return an HTTP 200 OK so KCB knows you received the notification

Tip: Always match incoming callbacks to your own records using transactionReference. Never trust a callback blindly - verify the amount and accounts match what you sent.


Sending Money to M-PESA

To transfer from a KCB account to an M-PESA wallet, use transaction type MO and set beneficiaryBankCode to MPESA:

{
  "transactionType": "MO",
  "beneficiaryBankCode": "MPESA",
  "creditAccountNumber": "2547XXXXXXXX",
  "beneficiaryDetails": "Jane Wanjiku",
  ...
}
Enter fullscreen mode Exit fullscreen mode

The creditAccountNumber in this case should be the recipient's phone number in the format 2547XXXXXXXX.


Sending to Other Banks

For inter-bank transfers (EFT, RTGS, Pesalink), you need the correct bank code for the recipient's bank. Here are the most common ones:

Bank Code
KCB 01
Equity Bank 68
Co-op Bank 11
NCBA 07
Stanbic Bank 31
I&M Bank 57
DTB 63
Family Bank 70
Absa 03
M-PESA MPESA

The full list is available in the API documentation appendix.


A Minimal Node.js Example

Here's a simple end-to-end example to get you oriented:

const axios = require('axios');

// Step 1: Get a token
async function getToken(consumerKey, consumerSecret) {
  const credentials = Buffer.from(`${consumerKey}:${consumerSecret}`).toString('base64');
  const response = await axios.post(
    'https://uat.buni.kcbgroup.com/token?grant_type=client_credentials',
    {},
    { headers: { Authorization: `Basic ${credentials}` } }
  );
  return response.data.access_token;
}

// Step 2: Initiate a transfer
async function sendTransfer(token) {
  const payload = {
    beneficiaryDetails: "John Doe",
    companyCode: "KE0010001",
    creditAccountNumber: "1234567890",
    currency: "KES",
    debitAccountNumber: "9876543210",
    debitAmount: 1000,
    paymentDetails: "Test payment",
    transactionReference: `PAY${Date.now()}`,  // unique reference
    transactionType: "IF",
    beneficiaryBankCode: "01"
  };

  const response = await axios.post(
    'https://uat.buni.kcbgroup.com/ft/transfer',  // confirm exact endpoint from KCB
    payload,
    { headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' } }
  );

  return response.data;
}

// Step 3: Callback handler (Express example)
app.post('/kcb/callback', (req, res) => {
  const { transactionReference, transactionStatus, amount } = req.body;

  if (transactionStatus === 'SUCCESS') {
    console.log(`Transfer ${transactionReference} succeeded - KES ${amount}`);
    // update your DB here
  } else {
    console.log(`Transfer ${transactionReference} FAILED`);
    // handle failure - notify user, reverse any internal state
  }

  res.status(200).send('OK');  // always acknowledge
});
Enter fullscreen mode Exit fullscreen mode

Common Beginner Mistakes to Avoid

1. Not saving the transactionReference
If you don't store it, you can't match the callback to your original request.

2. Confusing "Success" response with a completed transfer
A statusCode: "0" means accepted, not completed. Wait for the callback.

3. Not handling duplicate callbacks
KCB may retry sending the callback if your server returns a non-200 response. Make your callback handler idempotent - processing the same transactionReference twice should not double-credit or double-update.

4. Using production credentials in development
Always use Sandbox for testing. Real money moves in Production.

5. Hardcoding the transactionReference
It must be unique per request. Generate it dynamically.


Quick Reference

Item Detail
Sandbox Portal sandbox.buni.kcbgroup.com
Token Endpoint POST /token?grant_type=client_credentials
Auth Method OAuth 2.0 (Basic Auth with Consumer Key + Secret)
Request Type Async (result comes via callback)
Result Delivery POST to your Callback URL
Support Email buni@kcbgroup.com

Next Steps

  1. Register on the KCB Buni portal
  2. Create an application and subscribe to the FT API
  3. Set up a test callback URL (tools like Webhook.site or ngrok are useful here)
  4. Run a test internal transfer between the sandbox accounts KCB provides
  5. Inspect the callback payload your server receives
  6. Once confident, apply for Production access

For questions or integration support, reach out to the KCB Buni team at buni@kcbgroup.com or Whatsapp Me here

Top comments (0)