What You'll Learn
Understanding B2C Payments
B2C (Business to Customer) is a payment method that allows businesses to send money directly to customers' M-Pesa wallets. Unlike STK Push where customers pay you, B2C lets you initiate payments to your customers, employees, or any M-Pesa user.
SWIFT-WALLET's B2C API automates this process, allowing you to send money programmatically with automatic fee handling, real-time callbacks, and comprehensive transaction tracking.
Key Features
- Send money to any M-Pesa number instantly
- Automatic fee calculation and deduction
- Real-time transaction status updates
- Transaction history and reconciliation tools
- Batch payment support for payroll scenarios
When to Use B2C API
B2C payments are ideal for various business scenarios where you need to send money to individuals:
Common Use Cases
B2C Payment Use Cases
Payroll, Refunds, Rewards, and More
- Payroll Payments: Automate salary or commission payments to employees
- Customer Refunds: Return money to customers for cancelled orders or returned items
- Rewards and Cashback: Send promotional payments, bonuses, or loyalty rewards
- Marketplace Payouts: Transfer earnings to sellers, freelancers, or service providers
- Insurance Claims: Process and disburse claims to beneficiaries automatically
- Affiliate Payments: Pay commissions to partners or affiliates
- Gift Cards: Distribute digital vouchers or gift card balances
Perfect For
E-commerce refunds, marketplace platforms, HR systems, insurance companies, financial service providers, and any business that needs to send money to multiple recipients.
Prerequisites and Setup
Before integrating B2C payments, ensure you have:
- SWIFT-WALLET Account: Active account with sufficient wallet balance
- API Credentials: API key from your dashboard
- Wallet Balance: Sufficient funds to cover transfers and fees
- Callback URL: Secure HTTPS endpoint for receiving status updates
Wallet Balance Requirements
Before sending money via B2C, your wallet must have sufficient balance. The total cost of a B2C transfer includes:
- Transfer Amount: The amount you're sending to the recipient
- Transfer Fee: SWIFT-WALLET's fee for the B2C transaction
- M-Pesa B2C Fee: Safaricom's fee (automatically deducted)
Important
Always check wallet balance before initiating transfers. Insufficient balance will result in failed transactions. Use the Wallet API to query your balance first.
API Details and Parameters
B2C Endpoint
POST https://swiftwallet.co.ke/v3/pay-request/
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
phone_number |
string | Yes | Recipient phone number (254XXXXXXXXX) |
amount |
number | Yes | Amount to send (KES) |
reference |
string | Yes | Unique transaction reference |
callback_url |
string | Yes | HTTPS URL for status updates |
description |
string | No | Transaction description |
Initiating B2C Transfers
The process of sending money via B2C is straightforward:
- Check wallet balance
- Prepare transfer details
- Send API request
- Handle the response
- Process callbacks for status updates
Transaction Flow
When you initiate a B2C transfer:
- SWIFT-WALLET validates your request and checks wallet balance
- Funds are reserved for the transfer
- Safaricom's B2C API is called to send money to the recipient
- Recipient receives SMS notification on their phone
- Your callback URL receives status updates (initiated, completed, or failed)
- Transaction is logged in your dashboard
Fee Handling and Calculations
SWIFT-WALLET automatically handles all fee calculations. Fees are deducted from your wallet balance along with the transfer amount.
Fee Structure
B2C fees consist of two components:
- SWIFT-WALLET Fee: Transparent fee charged per transaction
- Safaricom B2C Fee: M-Pesa's standard B2C charges
Total Cost = Transfer Amount + SWIFT-WALLET Fee + Safaricom B2C Fee
Example: Sending 1,000 KES
- Transfer Amount: 1,000 KES
- SWIFT-WALLET Fee: 10 KES
- Safaricom B2C Fee: 12 KES
- Total Cost: 1,022 KES
- Recipient Receives: 1,000 KES
Query Fees
Use the Fees API to get accurate fee calculations before sending money. This helps you plan your expenses and ensures sufficient wallet balance.
Handling Callbacks
B2C callbacks provide real-time updates on transfer status:
Callback Status Values
- Initiated: Transfer request has been submitted to Safaricom
- Processing: Transfer is being processed by M-Pesa
- Completed: Money has been successfully sent to recipient
- Failed: Transfer failed (insufficient balance, invalid number, etc.)
- Cancelled: Transfer was cancelled before completion
Callback Data
Each callback includes transaction ID, status, recipient phone, amount, fees, MPesa receipt number, and timestamp for full reconciliation.
Code Examples
PHP Example
function sendB2CPayment($phoneNumber, $amount, $reference, $description = '') {
// First, check wallet balance
$balance = getWalletBalance();
$estimatedTotal = $amount + 50; // Include fees (check via Fees API)
if ($balance < $estimatedTotal) {
throw new Exception('Insufficient wallet balance');
}
$url = 'https://swiftwallet.co.ke/v3/pay-request/';
$data = [
'api_key' => getenv('SWIFT_WALLET_API_KEY'),
'phone_number' => $phoneNumber,
'amount' => $amount,
'reference' => $reference,
'callback_url' => 'https://yoursite.com/b2c-callback',
'description' => $description
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return json_decode($response, true);
}
// Usage: Send 1000 KES to customer for refund
try {
$result = sendB2CPayment(
'254712345678',
1000,
'REFUND-12345',
'Refund for Order #12345'
);
if ($result['success']) {
echo "Transfer initiated! Transaction ID: " . $result['transaction_id'];
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
JavaScript (Node.js) Example
const axios = require('axios');
async function sendB2CPayment(phoneNumber, amount, reference, description = '') {
try {
// Check wallet balance first
const balanceResponse = await axios.get(
'https://swiftwallet.co.ke/v3/wallet/',
{ params: { api_key: process.env.SWIFT_WALLET_API_KEY } }
);
const estimatedTotal = amount + 50; // Include fees
if (balanceResponse.data.payment_wallet < estimatedTotal) {
throw new Error('Insufficient wallet balance');
}
// Send B2C payment
const response = await axios.post(
'https://swiftwallet.co.ke/v3/pay-request/',
{
api_key: process.env.SWIFT_WALLET_API_KEY,
phone_number: phoneNumber,
amount: amount,
reference: reference,
callback_url: 'https://yoursite.com/b2c-callback',
description: description
},
{
headers: { 'Content-Type': 'application/json' }
}
);
return response.data;
} catch (error) {
console.error('B2C Error:', error.response?.data || error.message);
throw error;
}
}
// Usage
sendB2CPayment('254712345678', 1000, 'REFUND-12345', 'Refund for Order')
.then(result => {
console.log('Transfer initiated:', result.transaction_id);
})
.catch(error => {
console.error('Payment failed:', error.message);
});
Python Example
import requests
import os
def send_b2c_payment(phone_number, amount, reference, description=''):
# Check wallet balance
balance_url = 'https://swiftwallet.co.ke/v3/wallet/'
balance_params = {'api_key': os.getenv('SWIFT_WALLET_API_KEY')}
balance_response = requests.get(balance_url, params=balance_params)
balance_data = balance_response.json()
estimated_total = amount + 50
if balance_data['payment_wallet'] < estimated_total:
raise ValueError('Insufficient wallet balance')
# Send B2C payment
url = 'https://swiftwallet.co.ke/v3/pay-request/'
payload = {
'api_key': os.getenv('SWIFT_WALLET_API_KEY'),
'phone_number': phone_number,
'amount': amount,
'reference': reference,
'callback_url': 'https://yoursite.com/b2c-callback',
'description': description
}
response = requests.post(url, json=payload)
return response.json()
# Usage
try:
result = send_b2c_payment(
'254712345678',
1000,
'REFUND-12345',
'Refund for Order #12345'
)
if result.get('success'):
print(f"Transfer initiated! Transaction ID: {result['transaction_id']}")
else:
print(f"Error: {result['message']}")
except ValueError as e:
print(f"Error: {e}")
Batch Payment Example (PHP)
function processBatchPayroll($employees) {
$results = [];
foreach ($employees as $employee) {
try {
$reference = 'SALARY-' . date('Y-m') . '-' . $employee['id'];
$result = sendB2CPayment(
$employee['phone'],
$employee['salary'],
$reference,
'Salary for ' . date('F Y')
);
if ($result['success']) {
$results[] = [
'employee_id' => $employee['id'],
'status' => 'success',
'transaction_id' => $result['transaction_id']
];
} else {
$results[] = [
'employee_id' => $employee['id'],
'status' => 'failed',
'error' => $result['message']
];
}
} catch (Exception $e) {
$results[] = [
'employee_id' => $employee['id'],
'status' => 'failed',
'error' => $e->getMessage()
];
}
}
return $results;
}
// Example: Process monthly payroll
$employees = [
['id' => 1, 'phone' => '254712345678', 'salary' => 50000],
['id' => 2, 'phone' => '254723456789', 'salary' => 45000],
['id' => 3, 'phone' => '254734567890', 'salary' => 60000]
];
$payrollResults = processBatchPayroll($employees);
print_r($payrollResults);
Best Practices
- Always Check Balance First: Query wallet balance before initiating transfers to avoid failures
- Use Meaningful References: Create unique, descriptive transaction references for easy tracking
- Implement Retry Logic: Handle temporary failures gracefully with retry mechanisms
- Log Everything: Store transaction details in your database for auditing
- Handle Callbacks Properly: Process callbacks asynchronously and return 200 OK immediately
- Validate Phone Numbers: Ensure phone numbers are in correct format (254XXXXXXXXX)
- Set Up Monitoring: Track failed transfers and set up alerts for issues
- Test Thoroughly: Test with small amounts before processing large batch payments
Pro Tip
For payroll or batch payments, implement a queue system to process transfers sequentially, preventing rate limit issues and ensuring reliable delivery.