Bonaventure OgetoBy Bonaventure Ogeto|

Paystack Transfers to Paybill and Till Numbers

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.

Paybill vs Till: What Developers Need to Know

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.

FeaturePaybillTill (Buy Goods)
M-Pesa menuLipa na M-Pesa > Pay BillLipa na M-Pesa > Buy Goods
IdentifiersBusiness number + account numberTill number only
Use caseUtilities, rent, school fees, subscriptionsRetail purchases, restaurants, fuel
Account routingYes (account number routes within the business)No (flat payment)
Common examplesKPLC (888880), Nairobi WaterLocal shops, Uber, restaurants

Creating a Paybill Transfer Recipient

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:

  • Check the current API structure. The exact fields for Paybill recipients may differ from what is shown above. Paystack's API documentation for Kenya-specific transfer recipients is the source of truth. The metadata approach shown here is a common pattern, but Paystack may use a dedicated field for the account number. Always test in sandbox first.
  • The account number is critical. If you send money to the right Paybill number but with the wrong account number, the receiving business may not be able to allocate your payment. For utilities like KPLC, this means your customer's meter does not get topped up.
  • Validate before sending. If the receiving business provides a validation API (some do), use it to confirm the account number exists before creating the recipient and initiating the transfer.

Creating a Till Number Transfer Recipient

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.

Initiating the Transfer

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.

Real Use Cases for Paybill and Till Transfers

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.

How This Differs from Daraja B2B and B2C

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:

  • Simpler code. One transfer function handles all destination types. You do not need separate code paths for B2C vs B2B.
  • Less granular control. Daraja B2B lets you specify the command ID, the initiator, and other Safaricom-specific parameters. Paystack abstracts these away. If you need that level of control, Daraja is the better fit.
  • Paystack fees on top of M-Pesa fees. Direct Daraja B2B transactions have Safaricom's fee structure. Paystack adds its own transfer fee. For high-volume B2B payments, this cost difference matters.

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.

Verification and Reconciliation

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:

  1. Track the transfer status via webhooks. This confirms the money left your Paystack balance and reached the destination.
  2. Poll the receiving service if they have an API. Some large billers (utilities, telcos) provide APIs to check payment status. If available, use them to confirm the payment was applied.
  3. Ask the user to confirm. For smaller businesses without APIs, you may need the user to confirm receipt. "Did your landlord confirm the rent payment?" is a valid UX pattern when there is no automated alternative.
  4. Keep records. Store the Paystack transfer reference, the Paybill/Till number, the account number, the amount, the timestamp, and the webhook status. This is your audit trail if something goes wrong.
// 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',
};

Common Errors When Sending to Paybills and Tills

Transfers to business numbers have their own failure modes beyond what you see with personal M-Pesa wallets.

  • Wrong account number on Paybill. The money reaches the Paybill, but the receiving business cannot match it to a customer. Some businesses will reject the payment outright. Others will accept it and leave it in a suspense account. Getting it back requires contacting the business directly.
  • Inactive or suspended Paybill/Till. Businesses can have their M-Pesa merchant accounts suspended by Safaricom. Your transfer will fail. Handle this with a clear error message to the user.
  • Amount below minimum or above maximum. Some businesses set minimum and maximum transaction amounts on their Paybill or Till. If your transfer is outside that range, it will be rejected at the Safaricom level.
  • Business number does not exist. If the Paybill or Till number is invalid, the transfer will fail. Validate numbers before creating recipients, especially if the numbers come from user input.

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.

Next Steps

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.

Key Takeaways

  • Paystack Transfers can send money to M-Pesa Paybill numbers (business number + account number) and Till numbers (buy goods) in Kenya.
  • Paybill recipients require both the business number and the account number. The account number tells the receiving business which invoice or customer the payment is for.
  • Till number recipients only need the till number itself. There is no account number because buy goods transactions do not have sub-accounts.
  • Common use cases include utility bill payments, supplier payments, rent to landlord paybills, and automated business-to-business settlements.
  • The transfer flow is the same as M-Pesa wallet transfers: create recipient, initiate transfer, handle webhooks. The difference is in the recipient setup.
  • Always confirm the Paybill or Till number is correct before sending. Unlike personal M-Pesa transfers, business number mistakes can be harder to reverse.

Frequently Asked Questions

Can I send money to any Paybill number through Paystack Transfers?
You can send to Paybill numbers that are active on the M-Pesa network. The transfer goes through Safaricom infrastructure, so any Paybill that accepts M-Pesa payments should be reachable. However, verify the Paybill number and account number before sending, as errors in business payments can be difficult to reverse.
What is the difference between a Paybill transfer and a Till transfer?
A Paybill transfer requires a business number and an account number. The account number routes the payment within the receiving business (like a meter number for KPLC). A Till transfer only requires the till number. There is no sub-account routing. The recipient creation in Paystack reflects this difference.
How do I know if the receiving business processed my payment correctly?
Paystack confirms that the money left your balance and reached the destination. Whether the receiving business applied it correctly (e.g., generated an electricity token or credited the right account) depends on their system. Some businesses provide APIs to check payment status. For others, you may need manual confirmation from the user or the business.
Are there different fees for Paybill and Till transfers versus M-Pesa wallet transfers?
Paystack publishes its transfer fee schedule on paystack.com/pricing. Fees may vary by destination type and amount. Additionally, Safaricom applies its own charges for B2B transactions, which are separate from Paystack fees. Check both Paystack pricing and Safaricom tariffs for the complete cost picture.
Can I automate recurring payments to a Paybill through Paystack?
Yes. Create the Paybill recipient once and store the recipient code. Then schedule transfers using your own cron job or task scheduler. Paystack does not have a built-in recurring transfer feature, so the scheduling logic lives in your application. Make sure each scheduled transfer uses a unique reference for idempotency.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon