Paystack Transfers can send money to M-Pesa Paybill and Till numbers in Kenya. For Paybill, you create a transfer recipient with the business number as account_number, the business account number in the metadata or as part of the recipient details, and bank_code set accordingly. For Till, the till number serves as the account identifier. The transfer then works the same as any other Paystack transfer.
Before touching the API, you need to understand the difference between Paybill and Till numbers on M-Pesa. They are both ways businesses receive money, but they work differently.
Paybill numbers are used with the "Pay Bill" option in the M-Pesa menu. When a customer pays a Paybill, they enter two things: the business number (the Paybill number itself) and an account number. The account number is how the receiving business knows what the payment is for. KPLC uses it for your meter number. Your landlord uses it for your apartment unit. A school uses it for your admission number.
Till numbers are used with the "Buy Goods and Services" option. The customer only enters the till number. There is no account number field. Till numbers are common in retail: dukas, supermarkets, restaurants, petrol stations. The transaction is simple. Money goes from the customer to the business. No sub-routing needed.
This distinction matters when you set up transfer recipients in Paystack, because the data you provide for each type is different.
| Feature | Paybill | Till (Buy Goods) |
|---|---|---|
| M-Pesa menu | Lipa na M-Pesa > Pay Bill | Lipa na M-Pesa > Buy Goods |
| Identifiers | Business number + account number | Till number only |
| Use case | Utilities, rent, school fees, subscriptions | Retail purchases, restaurants, fuel |
| Account routing | Yes (account number routes within the business) | No (flat payment) |
| Common examples | KPLC (888880), Nairobi Water | Local shops, Uber, restaurants |
To send money to a Paybill through Paystack, you create a transfer recipient that includes both the business number and the account number. The exact field mapping depends on how Paystack structures Paybill recipients in Kenya.
const createPaybillRecipient = async (name, businessNumber, accountNumber) => {
const response = await fetch('https://api.paystack.co/transferrecipient', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_YOUR_SECRET_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'mobile_money',
name: name,
account_number: businessNumber,
bank_code: 'MPESA',
currency: 'KES',
metadata: {
account_number: accountNumber, // The sub-account within the Paybill
},
}),
});
const data = await response.json();
if (!data.status) {
throw new Error(data.message);
}
return data.data.recipient_code;
};
// Example: Pay KPLC electricity bill
// Business number: 888880, Account: your meter number
const kplcRecipient = await createPaybillRecipient(
'KPLC Prepaid',
'888880',
'12345678901' // Meter number
);
Important notes on the Paybill recipient setup:
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
Till number recipients are simpler because there is no account number to worry about. The till number is the only identifier.
const createTillRecipient = async (name, tillNumber) => {
const response = await fetch('https://api.paystack.co/transferrecipient', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_YOUR_SECRET_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'mobile_money',
name: name,
account_number: tillNumber,
bank_code: 'MPESA',
currency: 'KES',
}),
});
const data = await response.json();
if (!data.status) {
throw new Error(data.message);
}
return data.data.recipient_code;
};
// Example: Pay a hardware supplier
const supplierRecipient = await createTillRecipient(
'Kamau Hardware Supplies',
'5123456'
);
Once you have the recipient code, initiating the transfer works exactly the same as sending to an M-Pesa wallet. The M-Pesa wallet transfers article covers the initiation, OTP, and webhook handling in detail. The only difference is the recipient you pass.
With the recipient code in hand, the transfer call is identical regardless of whether the destination is a Paybill, a Till, or an M-Pesa wallet.
const paySupplier = async (recipientCode, amountKes, reason, reference) => {
const response = await fetch('https://api.paystack.co/transfer', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_YOUR_SECRET_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
source: 'balance',
amount: amountKes * 100, // Convert KES to cents
recipient: recipientCode,
reason: reason,
reference: reference,
}),
});
const data = await response.json();
return data;
};
// Pay KES 5,000 to the hardware supplier
await paySupplier(
'RCP_supplier_kamau',
5000,
'Invoice #INV-2026-0342 - PVC pipes',
'inv_0342_supplier_kamau_20260720'
);
// Pay KES 2,500 for KPLC electricity
await paySupplier(
'RCP_kplc_meter_123',
2500,
'Electricity token - July 2026',
'kplc_meter123_jul2026'
);
The reference field serves as your idempotency key. If your server crashes after sending the request but before saving the response, you can safely retry with the same reference. Paystack will not process the transfer twice.
After initiation, listen for transfer.success or transfer.failed webhooks. The webhook handling is the same as for M-Pesa wallet transfers. The event payload includes the reference, amount, and status.
Sending money to Paybills and Tills programmatically opens up several practical applications for Kenyan businesses.
Utility bill payments. Your app can pay KPLC, Nairobi Water, or other utility companies on behalf of your users. The user provides their meter or account number, you create the Paybill recipient and initiate the transfer. This is how utility payment apps work under the hood. See Building a Kenyan Utility Bill Payment Integration for a full build guide.
Supplier payments. An e-commerce platform or marketplace can pay suppliers automatically after a sale. The supplier has a Till number at their shop. When an order is confirmed and delivered, your system transfers the supplier's share to their Till. No one has to log into M-Pesa and type numbers manually.
Rent collection and disbursement. A property management platform collects rent from tenants (via Paystack checkout) and remits it to the landlord's Paybill or bank account, minus the management fee. See Building a Rent Collection Platform for Kenyan Landlords.
Subscription and service payments. Your SaaS product can automatically pay for third-party services that accept M-Pesa. Internet service providers, hosting companies, and tool subscriptions that use Paybill can all be paid programmatically.
B2B settlements. In multi-party platforms (marketplaces, aggregators), money flows from buyers to the platform to sellers. The sellers may be small businesses with Till numbers. Automated transfers close the loop. For the Daraja terminology mapping, see C2B, B2C, and B2B in Daraja Terms vs Paystack Terms.
If you are familiar with Safaricom's Daraja API, you know it has specific endpoints for different transaction types. Daraja separates B2C (business to customer, i.e., sending to personal M-Pesa wallets), B2B (business to business, i.e., sending to other Paybills or Tills), and Pay Bill (customer paying a business). Each has its own endpoint, parameters, and callback structure.
Paystack Transfers simplify this. From your perspective, every transfer is the same API call. The difference is only in the recipient setup. You create a recipient for a Paybill, a Till, a personal M-Pesa wallet, or a bank account. Then you call the same /transfer endpoint for all of them.
This simplification has trade-offs:
For teams already deep in the Paystack ecosystem, the simplicity wins. For teams doing heavy B2B payment volumes, direct Daraja may be more cost-effective. The Kenya pillar article covers this decision framework in full.
Paybill and Till transfers add a reconciliation challenge that M-Pesa wallet transfers do not have: you often need confirmation not just that the money was sent, but that the receiving business allocated it correctly.
For example, if you pay KPLC on behalf of a user, you need to confirm that the electricity token was generated. Paystack can tell you the transfer succeeded (money left your balance and reached the Paybill). But Paystack cannot tell you that KPLC processed the payment against the right meter number and generated a token. That confirmation has to come from KPLC's system or from the user.
Practical reconciliation steps:
// Example: reconciliation record structure
const paymentRecord = {
internalId: 'pay_20260720_kplc_001',
paystackReference: 'kplc_meter123_jul2026',
transferCode: 'TRF_abc123',
destinationType: 'paybill',
businessNumber: '888880',
accountNumber: '12345678901',
amountKes: 2500,
status: 'completed', // pending | completed | failed
paystackWebhookReceived: true,
billerConfirmed: false, // Set to true when KPLC confirms
createdAt: '2026-07-20T10:30:00Z',
completedAt: '2026-07-20T10:31:15Z',
};
Transfers to business numbers have their own failure modes beyond what you see with personal M-Pesa wallets.
For all error scenarios, the transfer.failed webhook will include a reason field. Log it, surface it to your operations team, and build workflows for investigating and retrying failed business payments.
Transfers to Paybills and Tills are one piece of the outbound payment puzzle. Here is where to go from here:
If you are building payment integrations for the Kenyan market and want structured training with project reviews, the McTaba M-Pesa/Daraja micro-course covers both the collection and payout sides of mobile money in Kenya. You ship a working integration, not just read about one.
KES 2,999
The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.
Start Paystack Course