ACHI
SYSTEMS
MPesa is Kenya’s leading mobile money service. Integrating it into HTML websites boosts payments. This guide explains the process step-by-step. You’ll learn Daraja API basics for beginners.
Why Integrate MPesa?
MPesa handles C2B payments easily. Customers pay via phone prompts. Websites gain trust with local options. E-commerce sites see higher conversions. It’s secure and fast for Kenyan users.
Key benefits include:
-
Instant STK Push notifications.
-
No extra apps needed.
-
Supports small businesses.
-
Tracks transactions live.
Prerequisites
Start with basics. You need a Safaricom developer account. Use Daraja API sandbox for tests. HTML alone can’t call APIs. Pair it with PHP, Node.js, or Python backend.
Gather these:
-
Consumer Key and Secret.
-
Paybill or Till Number.
-
HTTPS server (required).
-
Text editor like VS Code.
-
Local server like XAMPP.
Step 1: Register on Daraja Portal
Visit developer.safaricom.co.ke. Sign up free. Log in to Daraja dashboard. Create a new app. Select C2B or LIPA NA MPESA.
Fill details:
| Field | Description |
|---|---|
| App Name | Your website name |
| Company | Business name |
| Products | C2B, STK Push, etc. |
| Callback URL | Your confirmation endpoint |
Save keys. Note them securely. Test in sandbox first.
Step 2: Get OAuth Access Token
Tokens authenticate requests. They expire hourly. Use PHP or JS to fetch.
Sample PHP code:
<?php
$consumerKey = 'your_key';
$consumerSecret = 'your_secret';
$credentials = base64_encode($consumerKey . ':' . $consumerSecret);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials");
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: Basic ' . $credentials));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
curl_close($curl);
$token = json_decode($response)->access_token;
echo $token;
?>
Copy this to get_token.php. Run it. Save token for STK Push.
Step 3: Create HTML Payment Form
Build a simple form. Collect phone and amount. Submit to backend.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pay with MPesa</title>
<style>
body { font-family: Arial; max-width: 500px; margin: 50px auto; }
input { width: 100%; padding: 10px; margin: 10px 0; }
button { background: #00A651; color: white; padding: 15px; border: none; width: 100%; }
</style>
</head>
<body>
<h1>Buy Now - KSh 500</h1>
<form action="stk_push.php" method="POST">
<label>Phone Number:</label>
<input type="tel" name="phone" placeholder="2547XXXXXXXX" required pattern="254[17][0-9]{8}">
<label>Amount:</label>
<input type="number" name="amount" value="500" min="1" required>
<button type="submit">Pay with MPesa</button>
</form>
</body>
</html>
This form is mobile-friendly. Validates Kenyan numbers.
Step 4: Implement STK Push Backend
Create stk_push.php. Use token from Step 2. Send to MPesa API.
<?php
include 'get_token.php'; // Include token logic
$phone = $_POST['phone'];
$amount = $_POST['amount'];
$account = 'your_paybill'; // e.g., 600000
$transaction = 'TXN' . time();
$passkey = 'your_lipa_na_mpesa_passkey';
$shortcode = '174379'; // Sandbox shortcode
$timestamp = date('YmdHis');
$password = base64_encode($shortcode . $passkey . $timestamp);
$data = [
'BusinessShortCode' => $shortcode,
'Password' => $password,
'Timestamp' => $timestamp,
'TransactionType' => 'CustomerPayBillOnline',
'Amount' => $amount,
'PartyA' => $phone,
'PartyB' => $account,
'PhoneNumber' => $phone,
'CallBackURL' => 'https://yourdomain.com/callback.php',
'AccountReference' => 'YourWebsite',
'TransactionDesc' => 'Payment for order'
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curl);
curl_close($curl);
echo json_encode(json_decode($result, true));
?>
MPesa sends STK prompt to phone. Check CheckoutRequestID.
Step 5: Handle Callbacks
Callbacks confirm payments. Create callback.php. Log results.
<?php
$callback = file_get_contents('php://input');
file_put_contents('callbacks.txt', $callback . "\n", FILE_APPEND);
$data = json_decode($callback, true);
$resultCode = $data['Body']['stkCallback']['ResultCode'];
if ($resultCode == 0) {
$mpesaReceipt = $data['Body']['stkCallback']['CallbackMetadata'][0]['Value'];
// Update order status in DB
echo "Payment successful: " . $mpesaReceipt;
} else {
echo "Payment failed";
}
?>
Store in database for orders. Use MySQL for production.
Step 6: Check Transaction Status
Verify payments anytime. Create check_status.php.
<?php
$checkoutId = $_POST['checkout_id']; // From STK response
$data = [
'BusinessShortCode' => $shortcode,
'Password' => $password,
'Timestamp' => $timestamp,
'CheckoutRequestID' => $checkoutId
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://sandbox.safaricom.co.ke/mpesa/stkpushquery/v1/query');
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curl);
echo $result;
?>
Poll every 30 seconds if needed.
Security Best Practices
Protect your integration:
-
Never expose keys in HTML/JS.
-
Use HTTPS everywhere.
-
Validate inputs server-side.
-
Rate-limit API calls.
-
Log all transactions.
-
Rotate passkeys regularly.
Common errors:
| Error Code | Meaning | Fix |
|---|---|---|
| 1 | Success | |
| 2001 | Invalid phone | Check format |
| 1032 | Timeout | Retry later |
Testing in Sandbox
Use test credentials:
-
Shortcode: 174379
-
Passkey: bbf279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
-
Phone: 254708374149
Simulate payments. Go live after approval.
Going Live
Submit to Safaricom. Get production keys. Update URLs. Apply for Paybill via m-pesaforbusiness.co.ke. Expect 1-2 weeks approval.
Production endpoints swap “sandbox” for live.
Frontend Enhancements
Add JS for better UX:
document.querySelector('form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const response = await fetch('stk_push.php', { method: 'POST', body: formData });
const result = await response.json();
if (result.ResponseCode === '0') {
alert('Check your phone for MPesa PIN prompt!');
}
});
Shows progress without reloads.
Common Challenges
-
No STK Prompt: Check token, passkey.
-
Callback Issues: Ensure public HTTPS URL.
-
CORS Errors: Backend handles APIs.
-
Live Approval: Test thoroughly first.
Alternatives to Daraja
Consider IntaSend or Africa’s Talking for easier integration. Less setup, but fees apply.
Conclusion
MPesa integration transforms HTML sites. Follow these steps for success. Start sandbox today. Scale to live confidently.