Skip to main content

Paylink Widget (@palpluss/paylink)

Embed a Palpluss payment link into any website as a modal overlay or inline iframe. The widget is pure browser-side — your backend language (Node.js, PHP, Python, Laravel, Django, etc.) does not matter.
@palpluss/paylink is a frontend-only browser package. It has no dependency on @palpluss/sdk and runs entirely in the visitor’s browser. Your server never handles raw payment credentials.

Every integration — whether you use the npm package, the CDN script, or a raw iframe — starts with a paylink ID. Here is how to generate one from the Palpluss Console. Log in to the Palpluss Console and click Create Pay Link in the left sidebar under the SERVICES section. You will see the Generate Pay Link form with the following fields: Click Advanced Options to set an expiry date or additional restrictions. Once you have filled in the values you need, click the Generate Pay Link button at the bottom of the form. A modal will appear confirming the link was created:

Step 3 — Copy only the ID

The full URL has this format:
You only need the ID portion — the UUID that comes after the last /. In the example above that is:
This is the value you pass to pay(), the <PalplussPayment> component, or the src attribute of the raw iframe:
You can click Preview in the modal to open the payment page in a new tab and confirm it looks correct before sharing it with customers.

How It Works

  1. pay() creates a modal overlay and injects an <iframe> pointing to https://link.palpluss.com/{id}?embed=1.
  2. The embedded page communicates back via window.postMessage.
  3. On success the Promise resolves with { txId, amount, phone }. On close/cancel it rejects.
The iframe origin is https://link.palpluss.com — your page never handles raw M-PESA credentials or STK callbacks.

Installation (JavaScript / TypeScript only)

If you use PHP, Python, Ruby, or any other server-side language, skip this section and jump directly to Any Backend — Raw iframe. The npm package is only needed for JavaScript/TypeScript projects.
React peer dependencies are only needed if you import @palpluss/paylink/react:

Quick Start

Get your paylink ID from the Palpluss Console → Payment Links.

API Reference

pay(paylinkId, options?)

Opens a full-screen modal containing the payment iframe. Returns a Promise<PaymentResult> that:
  • resolves when the customer completes payment
  • rejects with Error('Payment modal closed by user') when the modal is dismissed
PayOptions

Pre-filling the payment form

Available from @palpluss/paylink 1.4.0.
Pass amount, phone and customerName to save your customer typing — for example when the amount comes from your cart and you already know their number.
  • Merchant-fixed values always win. If the paylink was created with a fixed amount or phone, that value is used and the pre-fill is ignored. The Palpluss API enforces this too, so a pre-fill can never change a merchant’s price.
  • Invalid values throw a TypeError (e.g. amount: 0, a name over 120 characters), so pay() rejects immediately and the mistake shows up during development.
  • A phone number that isn’t a valid Kenyan number is left blank so the customer can type it.
lockPrefill: true makes the pre-filled fields read-only, but it is a convenience, not a security control — the values travel in the iframe URL, which can be edited. If the amount must be guaranteed, create the paylink with a fixed amount (in the Console or via @palpluss/sdk), and always confirm the paid amount on your server before fulfilling an order.

openModal(paylinkId, options, resolve, reject)

Low-level function used internally by pay(). Exposed for advanced cases where you need direct control of the Promise lifecycle. Returns a cleanup() function that tears down the modal immediately.

buildPaylinkUrl(paylinkId, prefill?, { embed? })

Returns the URL of the hosted payment page with the same validated pre-fill — useful for raw iframes, server-rendered pages, or a shareable link.

<PalplussPayment> (React)

Import from @palpluss/paylink/react. Renders the payment iframe inline — no overlay, no modal — so you control layout and placement.
Pre-fill props follow the same rules as pay() (merchant-fixed values win). The iframe only reloads when one of them changes. The iframe starts at minHeight: 560px and auto-resizes via RESIZE postMessage events.

Usage Examples (JavaScript / TypeScript)


Any Backend — Raw Iframe

This section is for PHP, Python, Ruby, Go, .NET, and any other server-side language. The @palpluss/paylink npm package is entirely optional — it is just a convenience wrapper around a standard <iframe>. You can embed the payment widget using plain HTML and a small <script> block in any templating engine, CMS, or static site.

How it works without the npm package

The paylink widget is an <iframe> hosted at https://link.palpluss.com/{paylink-id}?embed=1. The ?embed=1 query parameter tells the Palpluss page it is running inside an embedded context. Once loaded, the iframe sends two types of postMessage events back to your page: Your page listens for these messages and reacts accordingly. No SDK or npm package required.

Minimal HTML snippet

Replace abc-123 with your actual paylink ID from the Palpluss Console.
The allow="payment" attribute grants the iframe access to the Payment Request API in supporting browsers. It does not affect functionality in environments that don’t support it.

Pre-filling the form with URL parameters

Add query parameters to the iframe src to pre-fill the payment form — no npm package needed. These are the same parameters pay() sends.
Build the URL server-side with proper encoding — for example in PHP:
or in Python:
Invalid values (an amount below 1, an unrecognised phone number) are ignored and the customer fills that field themselves. Merchant-fixed values on the paylink always take precedence, and lock is a convenience only — see the warning under Pre-filling the payment form.

Framework examples

In your Blade template, output the paylink ID from your controller or config. Everything else is plain HTML:
Pass $paylinkId from your controller:

postMessage event reference

Your message event listener receives event.data with the following shapes:
Always check e.data.type before acting on a message. Other libraries on your page (analytics, chat widgets, etc.) also use postMessage and your listener will receive those events too.

Security note on postMessage

The iframe is served from https://link.palpluss.com. For production applications, validate the message origin before trusting the payload:

TypeScript Types


How the Modal Works Internally

When pay() is called:
  1. Validation — pre-fill values are checked and the iframe URL is built (buildPaylinkUrl). Invalid values throw before anything is drawn.
  2. Native <dialog> — a <dialog> element (max-width: 860px, full-screen on phones) is opened with showModal(). It sits in the browser’s top layer, so no z-index is needed and page scroll is locked automatically.
  3. Iframe — src is https://link.palpluss.com/{id}?embed=1 plus any pre-fill parameters. ?embed=1 tells the Palpluss page it is running inside an SDK modal.
  4. Styles — injected once per page and shared by every modal.
  5. postMessage listener — listens for two event types from the iframe origin:
    • RESIZE — adjusts iframe.style.height for seamless auto-height.
    • PAYMENT_SUCCESS — extracts { txId, amount, phone }, calls onSuccess, removes the modal, resolves the Promise.
  6. Close handlers — the modal closes (and the Promise rejects) on:
    • Clicking the ✕ button
    • Clicking outside the dialog on the backdrop
    • Pressing Escape
  7. Cleanup — closes and removes the dialog and removes the message listener.

Relation to @palpluss/sdk

These are completely independent. A typical full-stack integration uses @palpluss/sdk on the server to create the paylink, and then the paylink widget (or raw iframe) on the frontend to collect payment: