Web Design

How to Integrate MPesa in HTML

24 Feb 2026 6 min read

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
<?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.

xml
<!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
<?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
<?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
<?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:

javascript
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.

Get a free quote for your project.

Tell us your goal - a faster site, more leads, or a security check - and we will reply with a clear plan and price.

Achi Systems · Madonna House, Westlands, Nairobi

Reach us directly