C2B, B2C, and B2B in Daraja Terms vs Paystack Terms
In Daraja terms, C2B (Customer to Business) maps to Paystack's Checkout or Charge API. B2C (Business to Customer) maps to Paystack Transfers. B2B (Business to Business) has no direct Paystack equivalent. STK Push maps to Paystack's mobile_money charge channel. The Daraja Validation URL has no Paystack equivalent because Paystack handles validation internally. The Daraja Confirmation URL maps to Paystack webhooks. Your Lipa Na M-Pesa shortcode is handled by Paystack internally.
Why the Vocabulary Gap Matters
If you have worked with Safaricom's Daraja API and then open the Paystack documentation, the first thing you notice is that nothing is called the same thing. Daraja talks about C2B, B2C, B2B, STK Push, Validation URLs, Confirmation URLs, shortcodes, and paybills. Paystack talks about Checkout, Charge, Transfers, webhooks, channels, and recipients.
They are doing the same work. Moving money between people and businesses in Kenya. But the language is so different that developers switching between the two (or running both side by side) waste hours translating concepts in their heads.
This article is the translation guide. It maps every major Daraja concept to its Paystack equivalent, explains where the mapping is clean and where it breaks down, and flags the things that exist in one system but not the other.
If you are migrating from Daraja to Paystack, this tells you which Paystack API replaces which Daraja endpoint. If you are running both, this tells you where the concepts overlap and where they diverge. If you are evaluating which to use, this tells you what each system can and cannot do.
The Complete Concept Mapping Table
Here is the full mapping. Each row shows a Daraja concept, its Paystack equivalent (if one exists), and notes on how they differ.
| Daraja Concept | Paystack Equivalent | Notes |
|---|---|---|
| C2B (Customer to Business) | Checkout / Transaction Initialize / Charge API | Daraja C2B is M-Pesa only. Paystack accepts M-Pesa, cards, Pesalink, bank transfers, Airtel Money, and Apple Pay through one API. |
| B2C (Business to Customer) | Transfers API | Daraja B2C sends M-Pesa only. Paystack Transfers send to M-Pesa wallets, bank accounts, and paybill numbers. |
| B2B (Business to Business) | No equivalent | Paystack does not support paybill-to-paybill or till-to-till transfers. Use Daraja directly. |
| STK Push (Lipa Na M-Pesa Online) | Charge API with mobile_money channel | Both trigger a prompt on the customer's phone. Paystack wraps Daraja's STK Push internally. |
| C2B Register URL (Validation + Confirmation) | Webhook URL (dashboard setting) | Daraja registers per-shortcode URLs. Paystack uses a single webhook URL for all events. |
| Validation URL | No equivalent | Paystack validates payments internally. You cannot accept or reject a payment before it processes. |
| Confirmation URL | Webhook (charge.success event) | Both notify you when payment completes. Different format and delivery mechanism. |
| STK Push Callback URL | Webhook (charge.success event) | Daraja sends to a per-request URL. Paystack sends all events to one webhook URL. |
| STK Push Query API | Verify Transaction API | Both let you poll for transaction status. Different endpoints, same purpose. |
| Lipa Na M-Pesa Shortcode | Handled internally by Paystack | You do not manage your own shortcode on Paystack. Paystack uses its own. |
| Paybill Number | Handled internally by Paystack | Your customers see Paystack's paybill, not yours. |
| Till Number | Not applicable | Paystack does not expose till number payments. All M-Pesa goes through STK push. |
| Account Reference | Transaction Reference | Daraja's AccountReference appears on the M-Pesa confirmation SMS. Paystack's reference is internal. |
| Transaction Type (CustomerPayBillOnline, CustomerBuyGoodsOnline) | channel: 'mobile_money' | Paystack abstracts the M-Pesa transaction type. You do not choose between paybill and buy goods. |
| PassKey | Secret Key | Different authentication mechanisms. Daraja uses PassKey + shortcode. Paystack uses a bearer token. |
| Consumer Key / Consumer Secret | Public Key / Secret Key | Both are API credential pairs. Daraja uses OAuth2 for access tokens. Paystack uses the secret key directly. |
| Access Token (OAuth) | Not needed | Daraja requires an OAuth token refresh every hour. Paystack uses the secret key directly in the Authorization header. |
| Transaction Status API | Verify Transaction API / List Transactions API | Both let you check what happened with a transaction. |
| Account Balance API | Balance API (/balance) | Daraja returns your M-Pesa balance. Paystack returns your Paystack balance (which may include funds from multiple channels). |
| Reversal API | Refund API | Daraja reverses M-Pesa transactions. Paystack refunds transactions (any channel). Similar purpose, different scope. |
This table covers the main mapping. The sections below go deeper into the most important rows.
C2B: Collecting Money from Customers
In Daraja, C2B (Customer to Business) is the API that lets customers send money to your paybill or till number. There are two C2B flows:
- STK Push (Lipa Na M-Pesa Online). You trigger a payment prompt on the customer's phone from your server. The customer enters their PIN. The money moves.
- Manual paybill payment. The customer opens their M-Pesa menu, selects "Lipa Na M-Pesa," enters your paybill number and account number, and sends the money. You receive this via the C2B Register URL callback.
On Paystack, both of these map to the "collect payments" side of the API, but with important differences:
STK Push maps to the Charge API. You call POST /charge with mobile_money.provider: "mpesa" and the customer's phone number. Paystack triggers the STK push on their side.
// Daraja STK Push
const darajaPayload = {
BusinessShortCode: '174379',
Password: base64Password,
Timestamp: timestamp,
TransactionType: 'CustomerPayBillOnline',
Amount: 1500,
PartyA: '254712345678',
PartyB: '174379',
PhoneNumber: '254712345678',
CallBackURL: 'https://yoursite.com/api/mpesa/callback',
AccountReference: 'Order123',
TransactionDesc: 'Payment for order',
};
// Paystack equivalent
const paystackPayload = {
email: 'customer@example.com',
amount: 150000, // cents
currency: 'KES',
mobile_money: {
phone: '0712345678',
provider: 'mpesa',
},
reference: 'order_123_1721472000',
};
Manual paybill payment has no direct Paystack equivalent. Paystack does not let your customers manually type in a paybill number to pay you. All M-Pesa payments on Paystack go through the STK push triggered by your API call. If you need to accept manual paybill payments (where the customer initiates the payment from their phone's M-Pesa menu), you need Daraja's C2B Register URL flow.
This is a real limitation. Some Kenyan businesses rely on customers paying via paybill without any website interaction. A shop with a paybill sticker on the counter, for example. Paystack does not serve this use case. Daraja does.
B2C: Sending Money to Customers
In Daraja, B2C (Business to Customer) lets you send money from your M-Pesa paybill to a customer's M-Pesa wallet. Common uses: salary payments, refunds, promotional payouts, agent float top-ups.
On Paystack, this maps to the Transfers API. The flow is:
- Create a transfer recipient (register the phone number or bank account).
- Initiate a transfer from your Paystack balance to the recipient.
- Listen for the
transfer.successortransfer.failedwebhook.
Key differences:
- Source of funds. Daraja B2C sends from your M-Pesa paybill balance. Paystack Transfers send from your Paystack balance. If your money is sitting in M-Pesa, you cannot use Paystack Transfers. You need to have funds in your Paystack balance first (from customer payments or a manual top-up if Paystack supports that for your account).
- Destinations. Daraja B2C sends to M-Pesa wallets only. Paystack Transfers can send to M-Pesa wallets, bank accounts, and paybill numbers. Paystack is more versatile here.
- Speed. Daraja B2C to M-Pesa is fast because it stays within the Safaricom network. Paystack Transfers to M-Pesa also go through Safaricom, but there may be an additional processing step on Paystack's end.
- Recipient management. Daraja does not require you to pre-register recipients. You just specify the phone number in each request. Paystack requires you to create a Transfer Recipient first, then use the recipient code in subsequent transfers. This adds a step but makes managing recurring payouts cleaner.
// Daraja B2C
const darajaB2C = {
InitiatorName: 'testapi',
SecurityCredential: encryptedCredential,
CommandID: 'BusinessPayment',
Amount: 500,
PartyA: '600123', // your shortcode
PartyB: '254712345678', // recipient phone
Remarks: 'Refund',
QueueTimeOutURL: 'https://yoursite.com/api/mpesa/timeout',
ResultURL: 'https://yoursite.com/api/mpesa/result',
};
// Paystack equivalent (two steps)
// Step 1: Create recipient
const recipient = {
type: 'mobile_money',
name: 'Jane Wanjiku',
account_number: '0712345678',
bank_code: 'MPESA',
currency: 'KES',
};
// Step 2: Initiate transfer
const transfer = {
source: 'balance',
amount: 50000, // KES 500 in cents
recipient: 'RCP_xxxxxxxxxx', // from step 1
reason: 'Refund for order 123',
};
If you are migrating from Daraja B2C to Paystack Transfers, the biggest change is adding the recipient creation step. Build a recipient cache so you do not create a new recipient for the same phone number every time.
B2B: The Gap in Paystack
Daraja B2B (Business to Business) lets you send money from one M-Pesa paybill to another. This is used for supplier payments, inter-company settlements, and bulk purchases from distributors.
Paystack does not support B2B in the M-Pesa sense. You cannot send money from your Paystack balance to another company's M-Pesa paybill through Paystack's API.
There is a partial workaround. Paystack Transfers can send to paybill numbers (as one of the recipient types). But this is technically a payout from your Paystack balance to the paybill, not a true M-Pesa B2B transaction. The distinction matters for accounting and for how the receiving business sees the payment in their M-Pesa statement.
If B2B payments are a core part of your application (paying suppliers, settling with partners, transferring between company accounts), you need Daraja. There is no Paystack substitute for this specific flow.
This is one of the key reasons some teams run both Paystack and Daraja. Paystack handles the customer-facing checkout (C2B). Daraja handles the backend financial operations (B2B, and sometimes B2C at scale). See Running Paystack and Daraja Side by Side for the implementation pattern.
Validation URL vs Confirmation URL vs Paystack Webhooks
This is the area where the Daraja-to-Paystack mapping gets most confusing. Let us break it down.
Daraja Validation URL: When a customer sends money to your paybill (via C2B), Safaricom first calls your Validation URL with the transaction details. Your server can inspect the payment (check the account number, verify the amount, check if the customer exists) and respond with either an "accept" or "reject" response. If you reject, the money goes back to the customer. This happens before the money moves.
Paystack equivalent: None. Paystack does not give you a pre-charge validation hook. When a customer pays via Paystack, the payment processes first, and then you get notified via webhook. You cannot reject a payment before it processes. If you need to reject or refund, you do it after the fact using the Refund API.
This is a significant difference for certain use cases. For example, a school fees portal using Daraja can validate the admission number before accepting the payment. If the admission number is wrong, the money bounces back instantly. On Paystack, you would accept the payment and then issue a refund, which is slower and creates more work for your operations team.
Daraja Confirmation URL: After a C2B payment is accepted (either through the Validation URL or by default), Safaricom calls your Confirmation URL with the final transaction details. This is your notification that the money has moved.
Paystack equivalent: Webhook (charge.success event). Both serve the same purpose: telling your server that a payment completed. The differences:
| Aspect | Daraja Confirmation URL | Paystack Webhook |
|---|---|---|
| Scope | One URL per shortcode, one callback per C2B transaction | One URL for all events across all payment channels |
| Event types | Only C2B confirmation | charge.success, transfer.success, refund.processed, subscription events, and more |
| Verification | No built-in signature verification (check source IP) | HMAC SHA-512 signature in the x-paystack-signature header |
| Retry on failure | Limited retries (Safaricom behavior varies) | Paystack retries with exponential backoff |
| Registration | Via the C2B Register URL API call | Set in the Paystack dashboard or via API |
Daraja STK Push Callback URL: Different from the C2B Confirmation URL. When you initiate an STK push, you specify a callback URL per request. Safaricom calls that URL with the result of the STK push (success, cancelled, timeout). Each STK push request can have a different callback URL.
Paystack equivalent: Same webhook URL. Paystack does not let you set a per-transaction callback URL for webhooks. All charge.success events go to your single registered webhook URL. You distinguish transactions by the reference in the payload. If you also set a callback URL when initializing the transaction, Paystack redirects the customer's browser to that URL after payment. But this is a browser redirect, not a server-to-server callback. They are different things.
Authentication: OAuth vs Secret Key
The authentication models are completely different, and this is one of the areas where Paystack is genuinely simpler.
Daraja authentication:
- You have a Consumer Key and Consumer Secret from the Safaricom developer portal.
- You use these to request an OAuth access token from the Daraja OAuth endpoint.
- The access token expires after one hour.
- You include the access token in the Authorization header of each API call.
- You need to handle token refresh. If your token expires mid-request, the call fails.
- For STK Push specifically, you also need a PassKey (provided by Safaricom) to generate the Password field.
Paystack authentication:
- You have a Public Key and a Secret Key from the Paystack dashboard.
- You include the Secret Key directly in the Authorization header:
Bearer sk_live_xxxx. - The key does not expire. No token refresh needed.
- The Public Key is used on the frontend (for the Paystack Inline JS popup). The Secret Key is used on the backend. Never expose the Secret Key on the frontend.
// Daraja: Get access token first
const tokenRes = await fetch(
'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
{
headers: {
Authorization: `Basic ${Buffer.from(
`${CONSUMER_KEY}:${CONSUMER_SECRET}`
).toString('base64')}`,
},
}
);
const { access_token } = await tokenRes.json();
// Then use it
const res = await fetch('https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(stkPayload),
});
// Paystack: Direct secret key, no token step
const res = await fetch('https://api.paystack.co/charge', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.PAYSTACK_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(chargePayload),
});
For developers who have wrestled with Daraja's OAuth token refresh (especially in serverless environments where there is no persistent process to cache the token), Paystack's approach is a relief. No token management. No refresh logic. One key, use it forever (or until you rotate it).
Concepts That Only Exist in Paystack
Paystack has features that Daraja does not, because Paystack is a full payment gateway, not just an M-Pesa API. If you are coming from a pure Daraja background, these are new concepts:
- Multi-channel checkout. One transaction can accept M-Pesa, card, Pesalink, bank transfer, and Apple Pay. Daraja only does M-Pesa.
- Plans and Subscriptions. Paystack has a built-in subscription engine. You create a plan (amount, interval, currency), and Paystack handles charging the customer on schedule. Daraja has no equivalent. If you need recurring M-Pesa charges on Daraja, you build the scheduling and retry logic yourself.
- Split Payments (Subaccounts). Paystack can automatically split a payment between multiple recipients at charge time. Useful for marketplace models where the platform takes a cut and the seller gets the rest. On Daraja, you would collect the full amount and then issue B2C payouts.
- Payment Pages. Paystack lets you create hosted payment pages (no-code) that customers can visit and pay. There is no Daraja equivalent. On Daraja, you always need a server to initiate the STK push.
- Dedicated Virtual Accounts. Paystack can assign a unique bank account number to each of your customers. When the customer transfers money to that account, Paystack credits your balance. This is a Nigeria-first feature but may be available in Kenya depending on Paystack's current offerings.
- Customer Objects. Paystack maintains a customer record across transactions. You can query all transactions for a customer, see their payment methods, and manage their data. Daraja does not have a customer concept. Transactions are linked by phone number, not by a customer ID.
- Transaction Metadata. You can attach arbitrary JSON metadata to a Paystack transaction. Daraja has the AccountReference field, but it is a single string, not a structured data field.
If you need any of these features, Paystack is the faster path. Building subscriptions, split payments, or payment pages on top of raw Daraja is a significant engineering effort.
Concepts That Only Exist in Daraja
Daraja has capabilities that Paystack does not expose, because Daraja gives you raw access to the M-Pesa platform:
- B2B transfers. Paybill to paybill. Not available on Paystack.
- Validation URL (pre-charge validation). Accept or reject a payment before money moves. Not available on Paystack.
- Manual paybill/till payments. Customers can pay by entering your paybill number from their phone's M-Pesa menu. Paystack only supports STK push (triggered from your server).
- Your own shortcode. On Daraja, the customer sees your business's paybill or till number. On Paystack, they see Paystack's. For some businesses, having their own number visible matters for brand trust.
- Transaction reversal with control. Daraja's Reversal API lets you reverse a specific M-Pesa transaction. Paystack's Refund API achieves a similar result but works at the Paystack layer, not directly at the M-Pesa layer.
- Account Balance query for M-Pesa. Daraja's Account Balance API returns your M-Pesa float balance. Paystack's Balance API returns your Paystack balance, which is a different thing.
- Buy Goods (Till) transaction type. Daraja distinguishes between paybill payments and buy goods (till) payments. They have different transaction types, different shortcode formats, and different fee structures. Paystack abstracts this away.
If any of these are critical to your application, Daraja is the tool for the job. Paystack cannot replicate them because it sits above the M-Pesa layer. It uses Daraja internally but does not expose all of Daraja's capabilities to you.
Which System Fits Your Needs
Now that you know the mapping, here is a practical decision framework based on what you actually need to do:
| What you need to do | Use |
|---|---|
| Collect M-Pesa payments via STK push | Either (Paystack is faster to implement) |
| Collect M-Pesa + card + Pesalink | Paystack |
| Accept manual paybill payments | Daraja |
| Validate payments before accepting | Daraja |
| Send money to M-Pesa wallets | Either (Daraja is more direct) |
| Send money between paybills (B2B) | Daraja only |
| Recurring subscription billing | Paystack (built-in) |
| Split payments at charge time | Paystack (built-in) |
| Show your own paybill to customers | Daraja |
| Accept payments from multiple African countries | Paystack |
Most Kenyan startups that need a checkout page will land on Paystack (or a similar gateway). Most businesses that need deep M-Pesa operations will keep Daraja. Many will use both. The vocabulary gap should not be the reason you choose one over the other. Now that you have the translation table, the terminology is no longer a barrier.
For the full comparison of when to use each system, see Paystack vs Daraja: When to Use a Gateway and When to Go Direct. For the mechanics of running both in one codebase, see Running Paystack and Daraja Side by Side.
Key Takeaways
- ✓C2B (Customer to Business) in Daraja maps to Paystack Checkout, the Charge API, or Transaction Initialize. Both let you collect money from a customer. The difference is that Daraja gives you a raw M-Pesa pipe while Paystack gives you a multi-channel checkout.
- ✓B2C (Business to Customer) in Daraja maps to Paystack Transfers. Both let you send money from your account to a customer or recipient. Paystack Transfers support M-Pesa wallets, bank accounts, and paybill numbers.
- ✓B2B (Business to Business) in Daraja has no Paystack equivalent. If you need to send money from one M-Pesa paybill to another, you must use Daraja directly.
- ✓STK Push (Lipa Na M-Pesa Online) maps to Paystack's Charge API with the mobile_money channel and provider set to "mpesa." Both trigger a push notification on the customer's phone.
- ✓The Daraja Validation URL has no Paystack equivalent. Paystack handles payment validation internally before processing the charge.
- ✓The Daraja Confirmation URL maps to Paystack webhooks. Both notify your server when a payment is completed. The mechanism is different (Daraja sends per-transaction callbacks, Paystack sends events to a single webhook URL) but the purpose is the same.
- ✓Paystack adds concepts that Daraja does not have: multi-currency support, split payments, subscriptions and plans, payment pages, and dedicated virtual accounts.
Frequently Asked Questions
- Can Paystack do everything Daraja can?
- No. Paystack cannot do B2B (paybill to paybill) transfers, pre-charge validation (Validation URL), manual paybill payments, or expose your own shortcode to customers. These are Daraja-only capabilities. Paystack covers C2B (via STK push) and B2C (via Transfers), plus multi-channel checkout, subscriptions, and split payments that Daraja does not offer.
- Is the Daraja Confirmation URL the same thing as a Paystack webhook?
- They serve the same purpose (notifying your server when a payment completes), but the mechanism is different. Daraja sends a per-shortcode callback to the registered Confirmation URL. Paystack sends all events to a single webhook URL. Paystack includes an HMAC signature for verification. Daraja does not include a built-in signature (you verify by source IP or other means).
- Why does Paystack not have a Validation URL equivalent?
- Paystack is designed as a gateway where payments are processed and then verified. The pre-charge validation model (accept or reject before money moves) is specific to the M-Pesa C2B flow on Daraja. Paystack processes the payment first, then notifies you. If you need to reject a payment, you issue a refund after the fact.
- What is the Paystack equivalent of the Daraja PassKey?
- There is no direct equivalent. The Daraja PassKey is used alongside the shortcode and timestamp to generate the Password field for STK Push requests. It is an extra authentication layer specific to Safaricom. Paystack uses a simpler model: your Secret Key in the Authorization header. No PassKey, no timestamp-based password generation.
- If I am migrating from Daraja to Paystack, what is the biggest change in my code?
- The biggest change is moving from per-request callback URLs to a single webhook URL that handles multiple event types. In Daraja, each STK Push request specifies its own callback URL. In Paystack, all charge.success events go to one webhook URL. You distinguish transactions by the reference in the event payload. The second biggest change is dropping the OAuth token management and using Paystack's secret key directly.
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