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

- URL: https://palpluss.com/blog/integrate-payments-5-lines-of-code
- Published: 2026-11-03 · Updated: 2026-11-03
- Author: PalPluss Engineering (Palpluss)

## Summary
- 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](https://palpluss.com/products) 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

```ts
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](https://console.palpluss.com) 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

```bash
npm install @palpluss/paylink
```

The 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

```html
<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

```tsx
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`.

```ts
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.com` inside 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.

> **Confirm on your server before you deliver:** The `pay()` result is a great signal for your UI, but anything that runs in a browser can be tampered with. Before you ship goods or unlock access, confirm the payment server-side: receive the PalPluss webhook, or look the transaction up with `GET /v1/transactions/{id}` and check it is `SUCCESS` for the expected amount. `lockPrefill` is a convenience, not a price guarantee — use a fixed-amount paylink when the price must not change.

```ts
// 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](https://palpluss.com/blog/automate-mpesa-stk-push-payments) |
| Sending money out to customers | [B2C payouts API](https://palpluss.com/blog/integrate-mpesa-b2c-automatic-payouts) |

> **Try it now:** [Create a free PalPluss account](https://console.palpluss.com/register), make a paylink, and paste the three lines above. Full options live in the [@palpluss/paylink README](https://www.npmjs.com/package/@palpluss/paylink).

## FAQ

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