Accept M-Pesa payments on your own website. You create a charge from your server, we return a hosted checkout link, the customer pays, and the money lands in your MoahBoost gateway balance minus the platform fee. Withdraw to M-Pesa whenever you like.
https://moahboost.com/api/v1/gw · authentication is your secret API key in the Authorization header. Keys are shown once when generated in the dashboard.Authorization: Bearer mbg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Every new account receives a live key automatically at signup, so you can start calling the API without any setup step. The key is displayed once in your dashboard on green, with a copy button, and is never shown again.
Test keys start with mbg_test_, live keys with mbg_live_. Only a SHA-256 hash is stored on our side. Generate extra keys, or revoke one, in the dashboard; a revoked key stops working instantly.
curl -X POST https://moahboost.com/api/v1/gw/payment \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 250,
"reference": "INV-1042",
"description": "Order 1042",
"customer_name": "Jane Wanjiku",
"customer_phone": "254712345678"
}'
reference is your own idempotency key. Send the same reference twice and you get the same charge back instead of a duplicate.
{
"ok": true,
"reference": "mbg_544ea7d0b30280118d",
"status": "pending",
"amount": 250,
"currency": "KES",
"fee_percent": 3,
"checkout_url": "https://moahboost.com/pay/mbg_544ea7d0b30280118d"
}
Redirect the customer to checkout_url to pay. Keep the returned reference, it is how you and we identify the charge.
curl "https://moahboost.com/api/v1/gw/payment?ref=mbg_544ea7d0b30280118d" \ -H "Authorization: Bearer YOUR_KEY"
{
"ok": true,
"payment": {
"reference": "mbg_544ea7d0b30280118d",
"merchant_ref": "INV-1042",
"amount": 250, "fee": 7.5, "net": 242.5,
"status": "paid", "rail": "mpesa",
"paid_at": "2026-10-28T19:55:46Z"
}
}
Status values: pending, paid, failed, cancelled. Poll this endpoint, or rely on the hosted checkout page which confirms to the customer automatically.
{ "ok": true, "balance": 1240.5, "currency": "KES", "status": "active" }
curl -X POST https://moahboost.com/api/v1/gw/payout \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount": 1000, "phone": "254712345678" }'
Minimum withdrawal KSh 50. The amount is deducted from your balance the moment the request is accepted, so the same money can never be requested twice. A rejection is refunded to your balance automatically.
approved and then paid with the M-Pesa transaction reference in your dashboard.Returns every rail currently available on the hosted checkout: M-Pesa in KES, Korapay in NGN (bank, card, transfer), and the Payza rails (card in USD, plus Malawi MWK, Sierra Leone SLL, DR Congo CDF, Zambia ZMW, Uganda UGX, Ghana GHS, Rwanda RWF). Each entry carries the currency and the rate used to convert your KES charge.
[{ "code": "mpesa", "label": "M-Pesa", "currency": "KES", "rate": 1, "min": 1, "max": 250000 },
{ "code": "payza_card", "label": "Card (Visa / Mastercard)", "currency": "USD", "rate": 0.007694, "min": 1, "max": 5000 }]
You do not have to choose a rail when you create a payment. Send the customer to checkout_url and the hosted page shows every rail you have enabled, converts your KES amount, and settles back into your KES balance at the same figure. Fees apply to the KES amount, not the rail amount.
Set a webhook URL in the dashboard. Every time a payment is confirmed we POST a JSON event to it, signed so you can prove it came from us.
X-MB-Event: payment.paid X-MB-Signature: sha256=4d1a...c9e Content-Type: application/json User-Agent: MoahBoost-Webhooks/1
{
"event": "payment.paid",
"created_at": "2026-10-28T20:31:05.118Z",
"data": {
"reference": "mbg_544ea7d0b30280118d",
"merchant_ref": "INV-1042",
"amount": 250, "fee": 7.5, "net": 242.5,
"status": "paid", "rail": "mpesa",
"paid_at": "2026-10-28T20:31:04.902Z"
}
}
const crypto = require("crypto");
function valid(rawBody, header, secret) {
var expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return header && header.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
The secret is shown in your dashboard. Use the raw request body bytes, not a re-serialised object, or the signature will not match.
From zero to your first paid order in five minutes.
POST /payment, sending the amount in KES.checkout_url we return. They pick M-Pesa, card or another rail and pay.A payment link is a fixed amount with a hosted checkout behind it. Create one in the dashboard, open it in a new tab to check the branding, then put it anywhere: an invoice, a WhatsApp message, a button on your site, or a QR code on your counter.
<a href="https://moahboost.com/pay/mbg_544ea7d0b30280118d"
style="display:inline-block;padding:13px 24px;border-radius:10px;
background:#8c52ff;color:#fff;font:700 15px system-ui;text-decoration:none">
Pay with M-Pesa
</a>
Each link appears in your payments list with its own status, so you can see at a glance who has paid.
One request creates the charge; the response carries the URL to send your customer to. Keep the key on the server.
$ch = curl_init("https://moahboost.com/api/v1/gw/payment");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 250,
"reference" => "INV-" . $order_id,
"description" => "Order #" . $order_id,
"customer_phone" => $phone
])
]);
$res = json_decode(curl_exec($ch), true);
header("Location: " . $res["checkout_url"]);
const res = await fetch("https://moahboost.com/api/v1/gw/payment", {
method: "POST",
headers: { Authorization: "Bearer YOUR_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ amount: 250, reference: "INV-" + orderId, description: "Order #" + orderId })
});
const { checkout_url } = await res.json();
res.redirect(checkout_url);
r = requests.post(
"https://moahboost.com/api/v1/gw/payment",
headers={"Authorization": "Bearer YOUR_KEY"},
json={"amount": 250, "reference": f"INV-{order_id}", "description": f"Order #{order_id}"},
timeout=30,
)
checkout_url = r.json()["checkout_url"]
Test keys (mbg_test_) are for building and integration checks. They work exactly like live keys, but nothing is charged until a customer completes the checkout, so you can create and abandon payments safely while you wire up your site.
payment.paid, and treat reference as the idempotency key.| Status | Meaning |
|---|---|
| 401 | Missing or revoked API key. |
| 400 | Validation failed, for example amount below 1 or a bad phone number. The error field explains what to fix. |
| 404 | Payment not found, or the reference belongs to another merchant. |
| 403 | Admin-only endpoint. |
1, maximum 500000 per charge.