B2C Pay-Request API

Send money to customer phone numbers using Safaricom M-Pesa B2C. This comprehensive guide will walk you through every step of implementing B2C payments.

B2C Transfer Flow
1
Initiate B2C Transfer

Send money transfer request to customer's phone

2
Customer Receives SMS

Customer receives M-Pesa notification

3
Money Transfer

M-Pesa processes the money transfer

4
Callback Notification

Receive real-time transfer status updates

Step-by-Step Implementation Guide

1

Get Your API Credentials

Before you can use the B2C Pay-Request API, you need to obtain your API credentials:

  • API Key: Your unique authentication token
  • Wallet Balances: Ensure you have sufficient funds in both payment and service wallets
  • M-Pesa Credentials: Your Safaricom M-Pesa B2C credentials (configured in the system)
Note: The B2C API requires both payment_wallet (for the amount being sent) and service_wallet (for withdrawal fees) to have sufficient balances.
2

Validate Phone Number Format

Ensure the phone number is in the correct format for M-Pesa B2C:

// Correct phone number formats "254712345678" // With country code (recommended) "0712345678" // Local format (will be converted)
Important: Phone numbers must be valid Kenyan mobile numbers registered with M-Pesa. The system will automatically format the number correctly.
3

Calculate Required Balances

Before initiating a B2C transfer, calculate the required wallet balances:

// Example calculation for sending 1000 KES const amount = 1000; const withdrawalFee = 15; // Standard M-Pesa B2C fee // Required balances: // payment_wallet: 1000 KES (amount to send) // service_wallet: 15 KES (withdrawal fee) const totalRequired = amount + withdrawalFee; // 1015 KES total
Fee Structure: M-Pesa B2C charges a flat fee of 15 KES for amounts up to 100,000 KES. Higher amounts may have different fee structures.
4

Make the API Request

Send a POST request to the B2C endpoint with the required parameters:

curl -X POST "http://localhost/pay-app/v3/pay-request/" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 1000, "phone_number": "254712345678", "command_id": "BusinessPayment", "remarks": "Payment for services", "occasion": "Service Payment", "external_reference": "PAY-001", "callback_url": "https://mysite.com/b2c-callback" }'
5

Handle the Response

Process the API response and handle different scenarios:

{ "success": true, "status": "INITIATED", "message": "B2C payment initiated successfully", "reference": "PAY-001", "transaction_id": 123, "originatorConversationID": "29115-34620561-1", "conversationID": "AG_20231201_1234567890", "amount_sent": 1000, "withdrawal_fee": 15, "phone_number": "2547****678", "command_id": "BusinessPayment", "wallet_balances": { "payment_wallet": 5000, "service_wallet": 485 } }
Success: The payment has been initiated. Monitor the transaction status through callbacks or by querying the transaction endpoint.
6

Handle Callbacks

Set up your callback endpoint to receive real-time status updates:

// Callback payload example { "success": true, "transaction_id": 123, "external_reference": "PAY-001", "originatorConversationID": "29115-34620561-1", "conversationID": "AG_20231201_1234567890", "transactionID": "LK4515154", "status": "completed", "timestamp": "2023-12-01T10:30:00+03:00", "withdrawal_fee": 15, "result": { "ResultCode": 0, "ResultDesc": "The service request is processed successfully." }, "transaction_info": { "phone_number": "254712345678", "amount": 1000, "currency": "KES", "transaction_type": "B2C" } }

Endpoint

POST
/v3/pay-request/
Requires both payment_wallet (amount) and service_wallet (withdrawal fee).

Request Parameters

Parameter Type Required Description Example
amount integer Yes The amount to send in KES (minimum 1, maximum 100,000) 1000
phone_number string Yes Recipient's phone number (with or without country code) "254712345678"
command_id string Optional M-Pesa command type (default: "BusinessPayment") "BusinessPayment"
remarks string Optional Additional remarks for the transaction "Payment for services"
occasion string Optional Occasion or purpose of the payment "Service Payment"
external_reference string Optional Your unique reference for tracking this transaction "PAY-001"
callback_url string Optional URL to receive status callbacks (must be HTTPS) "https://mysite.com/b2c-callback"
Parameter Validation:
  • Amount must be between 1 and 100,000 KES
  • Phone number will be automatically formatted to include country code
  • External reference must be unique per transaction
  • Callback URL must be a valid HTTPS endpoint

cURL Example

curl -X POST "http://localhost/pay-app/v3/pay-request/" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amount": 1000, "phone_number": "254712345678", "command_id": "BusinessPayment", "remarks": "Payment for services", "occasion": "Service Payment", "external_reference": "PAY-001", "callback_url": "https://mysite.com/b2c-callback" }'

Error Handling

400 - Bad Request
Invalid request parameters or missing required fields
{ "success": false, "error": "Validation failed", "message": "Amount must be between 1 and 100000", "details": { "amount": ["The amount field is required"] } }
401 - Unauthorized
Invalid or missing API key
{ "success": false, "error": "Unauthorized", "message": "Invalid API key provided" }
402 - Insufficient Funds
Insufficient wallet balance for the transaction
{ "success": false, "error": "Insufficient funds", "message": "Insufficient balance in payment_wallet", "required_amount": 1000, "available_balance": 500 }
500 - Server Error
Internal server error or M-Pesa service unavailable
{ "success": false, "error": "Internal server error", "message": "M-Pesa service temporarily unavailable" }

Success Response

{ "success": true, "status": "INITIATED", "message": "B2C payment initiated successfully", "reference": "PAY-001", "transaction_id": 123, "originatorConversationID": "29115-34620561-1", "conversationID": "AG_20231201_1234567890", "amount_sent": 1000, "withdrawal_fee": 15, "phone_number": "2547****678", "command_id": "BusinessPayment", "wallet_balances": { "payment_wallet": 5000, "service_wallet": 485 } }

Callbacks

Your callback endpoint will receive real-time updates about the transaction status:

{ "success": true, "transaction_id": 123, "external_reference": "PAY-001", "originatorConversationID": "29115-34620561-1", "conversationID": "AG_20231201_1234567890", "transactionID": "LK4515154", "status": "completed", "timestamp": "2023-12-01T10:30:00+03:00", "withdrawal_fee": 15, "result": { "ResultCode": 0, "ResultDesc": "The service request is processed successfully." }, "transaction_info": { "phone_number": "254712345678", "amount": 1000, "currency": "KES", "transaction_type": "B2C" } }
Callback Status Values:
  • initiated - Payment request sent to M-Pesa
  • completed - Payment successfully processed
  • failed - Payment failed (insufficient funds, invalid number, etc.)
  • cancelled - Payment was cancelled by user or system