How to Integrate Secure Payments in Your Platform in Less Than 5 Lines of Code
Embed a secure M-Pesa checkout in any website in under 5 lines with the PalPluss Paylink widget — vanilla JS, React and CDN examples, plus server checks.
- By
- PalPluss Engineering
- Published
- Reading time
- 5 min
The short answer
- The PalPluss Paylink widget (@palpluss/paylink) opens a hosted M-Pesa checkout from your site with a single pay() call — the whole integration fits in under 5 lines.
- The checkout runs on link.palpluss.com inside an iframe, so your site never handles the customer's payment details or your API key.
- For security, fix prices on the paylink itself and confirm each payment on your server before you deliver anything.
Not every team wants to build a checkout. If you run a course site, an event page, a SaaS dashboard or a WordPress store, you want customers to pay with M-Pesa today — without writing a backend payment flow, managing API keys in the browser or designing a payment form.
That is what PalPluss Paylinks are for. A paylink is a hosted M-Pesa payment page you create in the console. The @palpluss/paylink widget opens that page as a polished modal or inline embed on your own site — in fewer than five lines of code.
The whole integration
import { pay } from "@palpluss/paylink";
const result = await pay("your-paylink-id");
console.log("Paid", result.amount, "ref", result.txId);That is three lines. pay() opens a full-screen modal, the customer enters their M-Pesa number and approves the STK prompt on their phone, and the promise resolves with { txId, amount, phone }. If the customer closes the modal, it rejects — so wrap it in try/catch.
Step 1: Create a paylink
In the PalPluss console open Create Pay Link. Choose the payment channel, and decide whether the amount is fixed (a product with a price) or open (donations, tips, top-ups). Copy the paylink ID.
Step 2: Install the widget
npm install @palpluss/paylinkThe core pay() function is plain DOM with zero dependencies. React is optional and only needed for the React component.
Step 3: Pick your style
Plain HTML — no build step
<script src="https://cdn.jsdelivr.net/npm/@palpluss/paylink@1/dist/cdn/palpluss-paylink.global.js"></script>
<button onclick="Palpluss.pay('your-paylink-id').then(r => alert('Paid! Ref: ' + r.txId))">
Pay with M-Pesa
</button>React button
import { pay } from "@palpluss/paylink";
export function CheckoutButton({ paylinkId }: { paylinkId: string }) {
return (
<button onClick={() => pay(paylinkId).then(onPaid).catch(() => {})}>
Pay with M-Pesa
</button>
);
}Pre-fill the amount and phone
Already know the cart total and the customer's number? Pass them in so the customer only has to approve. Since v1.4.0 the widget accepts amount, phone, customerName and lockPrefill.
const result = await pay("your-paylink-id", {
amount: 1500,
phone: "0712345678",
customerName: "Jane Wanjiku",
lockPrefill: true,
});Why this is secure
- No secrets in the browser. The widget needs only a public paylink ID. Your API key stays on your server — or you don't need a server at all.
- The checkout is isolated. The payment form runs on
https://link.palpluss.cominside an iframe. Your page never sees or stores the customer's payment details. - Merchant prices always win. If the paylink has a fixed amount, any pre-filled amount is ignored — and the PalPluss API enforces it too, so a customer cannot change your price by editing the page.
- Payment events are verified. From v1.4.1 the widget only accepts messages from its own iframe on
https://link.palpluss.com, so other scripts or frames on your page cannot fake a successful payment. - Payments use M-Pesa's own PIN prompt. The customer approves on their phone, so card numbers and PINs never touch a web form.
- Abuse controls are on by default — per-number request limits and success-rate monitoring stop prompt spam against your customers.
// Called by your frontend with result.txId after pay() resolves
const tx = await palpluss.getTransaction(txId);
if (tx.status === "SUCCESS" && tx.amount === order.total) {
await grantAccess(order.id);
}When to use the widget vs the API
| You want… | Use |
|---|---|
| A checkout on a website in minutes, no payment backend | Paylink widget |
| Payments on WordPress, Webflow or a static site | Paylink widget (CDN script) |
| Full control of the flow inside your own app or USSD | STK Push API |
| Sending money out to customers | B2C payouts API |
Frequently asked questions
How do I accept M-Pesa payments on my website without a backend?
Create a paylink in the PalPluss console and open it with the @palpluss/paylink widget: import { pay } from '@palpluss/paylink' and call pay('your-paylink-id'). The hosted checkout handles the M-Pesa STK Push for you.
Is the PalPluss Paylink widget secure?
Yes. The checkout runs on link.palpluss.com inside an iframe, the browser only needs a public paylink ID, and fixed paylink prices are enforced by the API. For goods or access, confirm each payment server-side by webhook or transaction lookup before delivering.
Does the widget work with React?
Yes. Call pay() from any click handler, or use the PalplussPayment component from @palpluss/paylink/react for an inline embed. React is an optional peer dependency.
Can I pre-fill the amount and phone number?
Yes. From v1.4.0, pass amount, phone, customerName and lockPrefill in the pay() options. A fixed amount set on the paylink always takes priority.
Build on PalPluss
M-Pesa collections and payouts in one API. KES 15 in free tokens to start.