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.
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.
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.
Get weekly developer tips
Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.
No spam. Unsubscribe anytime.
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:
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.
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:
transfer.success or transfer.failed webhook.Key differences:
// 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.
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.
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.
The authentication models are completely different, and this is one of the areas where Paystack is genuinely simpler.
Daraja authentication:
Paystack authentication:
Bearer sk_live_xxxx.// 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).
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:
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.
Daraja has capabilities that Paystack does not expose, because Daraja gives you raw access to the M-Pesa platform:
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.
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.
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