Paysuit Docs
Choose the integration style that matches your stack. You can be live in minutes.
Quick start: If you are in any JavaScript framework, run
npm install paysuitjs. If you are in Python, run pip install paysuit-py. Method 3 is direct HTTP request payloads.Method 1: JavaScript / TypeScript SDK
Works with Next.js, React, Node.js, Nuxt, SvelteKit, and more.
npm install paysuitjsimport { createMpesaClient } from "paysuitjs";
const client = createMpesaClient({
baseUrl: "https://api.paysuit.co.ke",
apiKey: process.env.PAYSUIT_API_KEY!,
});
const response = await client.stkPush({
senderPhoneNumber: "254712345678",
amount: "10",
receiverBankPaybill: "174379",
receiverBankAccountNumber: "INV-2026-001",
transactionDescription: "Starter Plan",
});
console.log(response);Method 2: Python SDK
Great for Django, Flask, FastAPI, and server automation.
pip install paysuit-pyfrom paysuit import MpesaClient
client = MpesaClient(
base_url="https://api.paysuit.co.ke",
api_key="YOUR_API_KEY"
)
response = client.stk_push(
senderPhoneNumber="254712345678",
amount="10",
receiverBankPaybill="174379",
receiverBankAccountNumber="INV-2026-001",
transactionDescription="Starter Plan"
)
print(response)Method 3: Direct API Request + Webhook
Send raw HTTP requests and receive final payment outcomes on your webhook URL.
curl -X POST https://api.paysuit.co.ke/api/v1/stk_push \
-H "Content-Type: application/json" \
-H "X-API-Key: <YOUR_API_KEY>" \
-d '{
"senderPhoneNumber": "254712345678",
"amount": "10",
"receiverBankPaybill": "174379",
"receiverBankAccountNumber": "INV-2026-001",
"transactionDescription": "Starter Plan",
"callbackUrl": "https://yourapp.com/api/payments/webhook"
}'After sending STK Push, the final result should be consumed from your webhook endpoint so you can update your DB and notify the user in real time.
// app/api/payments/webhook/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const payload = await req.json();
// Example callback fields:
// payload.result_code, payload.result_description,
// payload.CheckoutRequestID, payload.MerchantRequestID, payload.metadata
if (payload.result_code === 0) {
// Mark payment as successful in DB and unlock product/service for user
// notifyUser(payload.CheckoutRequestID, "Payment successful ✅");
} else {
// notifyUser(payload.CheckoutRequestID, "Payment failed ❌");
}
// Always return 200 quickly so webhook retries don't pile up
return NextResponse.json({ ok: true });
}Reference SDK (TypeScript)
Starter implementation you can adapt if you want your own custom client package.
// src/index.ts
interface MpesaClientConfig {
baseUrl: string;
apiKey: string;
timeout?: number;
}
interface StkPushRequest {
senderPhoneNumber: string;
amount: string;
receiverBankPaybill?: string | null;
receiverBankAccountNumber?: string | null;
transactionDescription?: string;
}
interface StkPushResponse {
MerchantRequestID: string;
CheckoutRequestID: string;
ResponseCode: string;
ResponseDescription: string;
CustomerMessage: string;
}
export class MpesaClient {
private baseUrl: string;
private apiKey: string;
private timeout: number;
constructor(config: MpesaClientConfig) {
if (!config.baseUrl) throw new Error("baseUrl is required");
if (!config.apiKey) throw new Error("apiKey is required");
this.baseUrl = config.baseUrl.replace(/\/$/, "");
this.apiKey = config.apiKey;
this.timeout = config.timeout || 30000;
}
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(this.baseUrl + endpoint, {
...options,
headers: {
"Content-Type": "application/json",
"X-API-Key": this.apiKey,
...options.headers,
},
signal: controller.signal,
});
clearTimeout(timeoutId);
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || data.message || "HTTP " + response.status);
}
return data as T;
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === "AbortError") {
throw new Error("Request timeout");
}
throw error;
}
}
async stkPush(request: StkPushRequest): Promise<StkPushResponse> {
return this.request<StkPushResponse>("/api/v1/stk_push", {
method: "POST",
body: JSON.stringify(request),
});
}
}
export function createMpesaClient(config: MpesaClientConfig): MpesaClient {
return new MpesaClient(config);
}