Official React SDK for Malipopay. Ready-to-use checkout components, payment widgets, and hooks for accepting payments in Tanzania via Mobile Money (M-Pesa, Airtel Money, Mixx/YAS, Halopesa, T-Pesa), Bank Transfer, USSD, and Card.
npm install @malipopay/react
# or
yarn add @malipopay/reactThe React SDK does not take your API key directly — that would expose it in the browser. Instead, your backend creates payments using the server-side SDK and the React SDK calls your backend.
┌─────────┐ 1. user clicks pay ┌─────────┐ 3. collect() ┌───────────┐
│ React │ ────────────────────► │ Your │ ─────────────► │ Malipopay │
│ SDK │ ◄──────────────────── │ Backend │ ◄───────────── │ API │
└─────────┘ 4. open payment link └─────────┘ 2. reference └───────────┘
import express from "express";
import { Malipopay } from "malipopay";
const app = express();
app.use(express.json());
const client = new Malipopay(process.env.MALIPOPAY_API_KEY!);
app.post("/api/payments", async (req, res) => {
const payment = await client.payments.collect(req.body);
res.json(payment);
});
app.get("/api/payments/:ref/status", async (req, res) => {
const result = await client.payments.verify(req.params.ref);
res.json(result);
});import { MalipopayProvider } from "@malipopay/react";
function App() {
return (
<MalipopayProvider apiUrl="/api/payments">
<Checkout />
</MalipopayProvider>
);
}import { CheckoutButton } from "@malipopay/react";
function Checkout() {
return (
<CheckoutButton
payment={{
description: "Order #1234",
amount: 10000,
phoneNumber: "255712345678",
}}
onSuccess={(p) => console.log("Paid:", p.reference)}
onFailure={(err) => console.error(err)}
>
Pay TZS 10,000
</CheckoutButton>
);
}Single-click payment button. Creates a payment, opens the checkout, and polls for completion.
<CheckoutButton
payment={{ description: "...", amount: 10000, phoneNumber: "255712345678" }}
mode="popup" // "popup" | "newtab" | "redirect"
onSuccess={(payment) => {}}
onFailure={(error) => {}}
onCancel={() => {}}
>
Pay now
</CheckoutButton>Inline form with amount, phone, and description inputs.
<PaymentForm
amount={10000} // Optional: prefill & lock amount
description="Monthly subscription" // Optional: prefill & lock description
buttonLabel="Subscribe"
onSuccess={(p) => console.log(p)}
/>Embed a payment link as an iframe.
<PaymentLinkEmbed link={payment.link} height={700} />Live status with polling (pending → completed/failed).
<PaymentStatus
reference={payment.reference}
onFinal={(p) => console.log("Done:", p.status)}
/>Create a payment programmatically.
const { createPayment, payment, loading, error } = usePayment();
const handleClick = async () => {
const result = await createPayment({
description: "Order #1234",
amount: 10000,
phoneNumber: "255712345678",
});
window.location.href = result.link!;
};Poll a payment's status until a terminal state.
const { status, payment, polling } = usePaymentStatus({
reference: "PAY-abc123",
interval: 3000,
onFinal: (p) => console.log("Done:", p.status),
});Combines usePayment + usePaymentStatus. Opens a checkout window and polls.
const { checkout, payment, loading } = useCheckout();
await checkout(
{ description: "Order", amount: 10000, phoneNumber: "255712345678" },
{ mode: "popup", onSuccess: (p) => console.log(p) }
);<MalipopayProvider environment="uat"> // for testing
<MalipopayProvider environment="production"> // defaultimport { MalipopayError } from "@malipopay/react";
try {
await createPayment(...);
} catch (err) {
if (err instanceof MalipopayError) {
console.log("Status:", err.statusCode, "Code:", err.code);
}
}- React 17+
- A backend that uses the server-side Malipopay SDK
- Malipopay API key (get one here)
MIT
| SDK | Install |
|---|---|
| Node.js | npm install malipopay |
| Python | pip install malipopay |
| PHP | composer require malipopay/malipopay-php |
| Java | Maven / Gradle |
| .NET | dotnet add package Malipopay |
| Ruby | gem install malipopay |
| Flutter/Dart | flutter pub add malipopay |
| React | npm install @malipopay/react |