@obare13/pesapal-v3
v1.0.0
Published
Pure TypeScript PesaPal library for frontend frameworks
Maintainers
Readme
Pesapal TypeScript Library
A pure, dependency-free TypeScript library for the PesaPal API v3 using the standard Web Fetch API. Designed to work flawlessly in frontend frameworks like Next.js, Nuxt.js, SvelteKit (server routes) or standard Node.js applications (v18+).
The library was created to ease the usage of PesaPal payments in modern TypeScript/JavaScript environments.
[!WARNING] Consumer Keys and Secrets should never be exposed to the browser. Only use this library inside secure server-side routes (like Next.js API Routes or Server Actions).
Showcase
The library comes with three beautiful, ready-to-use examples for popular frameworks. They all share the same premium UI and robust payment logic.
| Next.js Example | Nuxt.js Example | SvelteKit Example |
| :---: | :---: | :---: |
|
|
|
|
Resources
To help you get started quickly, here are some useful links:
- Official Documentation: https://developer.pesapal.com/
- Postman Collection: Official PesaPal V3 Postman
- Test Credentials: Sandbox Demo Keys
Installation
npm install @obare13/pesapal-v3(Since you are developing locally, you can use npm link or copy this package directly to your project)
Usage
1. Initialize the client
import { PesapalClient } from '@obare13/pesapal-v3';
const pesapal = new PesapalClient({
consumerKey: process.env.PESAPAL_CONSUMER_KEY!,
consumerSecret: process.env.PESAPAL_CONSUMER_SECRET!,
environment: 'sandbox', // Use 'production' for live apps
});2. Authenticate & Register IPN
// Authenticate
await pesapal.authenticate();
// Register your server's IPN URL for instant payment notifications
const ipn = await pesapal.registerIPN({
url: "https://your-domain.com/api/pesapal-webhook", // Must be publicly accessible
ipn_notification_type: "GET"
});
const ipnId = ipn.ipn_id;
console.log('IPN Registration ID:', ipnId);3. Create an Order (Checkout)
const orderResponse = await pesapal.submitOrder({
id: "YOUR_UNIQUE_ORDER_ID_123",
currency: "KES",
amount: 100.0,
description: "Test Purchase",
callback_url: "https://your-domain.com/payment-success",
notification_id: ipnId, // From previous step
billing_address: {
email_address: "[email protected]",
phone_number: "0712345678",
country_code: "KE",
first_name: "John",
last_name: "Doe"
}
});
// Redirect user to the PesaPal checkout page
console.log('Redirect user to:', orderResponse.redirect_url);4. Verify Transaction Status
When a transaction is completed, PesaPal redirects the user and/or calls your IPN URL with an OrderTrackingId parameter. Use it to check status:
await pesapal.authenticate(); // Ensure you're still authenticated
const status = await pesapal.getTransactionStatus('ORDER_TRACKING_ID_HERE');
if (status.payment_status_code === 'COMPLETED') {
// Update your database!
console.log('Payment Successful:', status);
}Going to Production
To move from Sandbox to Production, follow these critical steps to ensure secure and successful payments.
1. Environment Configuration
Update your environment variables with your live credentials from the PesaPal Dashboard.
PESAPAL_CONSUMER_KEY=your_live_key
PESAPAL_CONSUMER_SECRET=your_live_secret
PESAPAL_ENVIRONMENT=production2. Update Client Initialization
Ensure your client is initialized with the 'production' environment.
const pesapal = new PesapalClient({
consumerKey: process.env.PESAPAL_CONSUMER_KEY!,
consumerSecret: process.env.PESAPAL_CONSUMER_SECRET!,
environment: 'production', // MUST be 'production' for live payments
});3. Handle IPNs Securely (Webhooks)
When PesaPal sends an IPN (Instant Payment Notification) to your server, you must verify the transaction status before updating your database.
Example: Next.js API Route (app/api/pesapal-webhook/route.ts)
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const orderTrackingId = searchParams.get('OrderTrackingId');
const orderNotificationId = searchParams.get('OrderNotificationId');
if (!orderTrackingId) return new Response('Missing ID', { status: 400 });
await pesapal.authenticate();
const status = await pesapal.getTransactionStatus(orderTrackingId);
if (status.payment_status_code === 'COMPLETED') {
// 1. Mark order as paid in your DB
// 2. Trigger post-payment logic (e.g. send email)
}
// Return exactly what PesaPal expects to acknowledge receipt
return Response.json({
orderNotificationId,
orderTrackingId,
status: 200
});
}Framework Setup
I have provided ready-to-use examples for popular frameworks. Each example includes a shared CheckoutForm component and secure API routes.
Next.js Example
- API Integration: Implements App Router API routes (
app/api/checkout/route.ts) to securely initialize payments. - Components: Uses Shadcn-inspired UI components for a premium look and feel.
- Setup:
- Copy
.env.exampleto.envand add your PesaPal keys. - Run
pnpm install && pnpm dev.
- Copy
Nuxt.js Example
- Server Routes: Uses Nitro server routes (
server/api/checkout.post.ts) for server-side logic. - Vue Integration: Features a reactive
CheckoutForm.vuecomponent with Tailwind CSS. - Setup:
- Add keys to
.envorruntimeConfiginnuxt.config.ts. - Run
pnpm install && pnpm dev.
- Add keys to
SvelteKit Example
- Server Actions: Leverages SvelteKit Form Actions (
+page.server.ts) for seamless form submission. - Modern Styling: Uses Svelte with Tailwind CSS for a fast and beautiful experience.
- Setup:
- Define keys in
.env(accessed via$env/static/private). - Run
pnpm install && pnpm dev.
- Define keys in
Error Handling
The library provides comprehensive error classes to help you easily debug and handle failures at different stages.
import {
PesapalClient,
PesapalAuthenticationError,
PesapalValidationError,
PesapalAPIError,
PesapalNetworkError
} from '@obare13/pesapal-v3';
try {
await pesapal.submitOrder(payload);
} catch (error) {
if (error instanceof PesapalValidationError) {
console.error("Missing fields or bad input data:", error.message);
} else if (error instanceof PesapalAuthenticationError) {
console.error("Token invalid or expired:", error.message);
} else if (error instanceof PesapalAPIError) {
console.error("PesaPal API returned an error:", error.message, error.response);
} else if (error instanceof PesapalNetworkError) {
console.error("Fetch request failed totally (e.g. timeout)", error.message);
} else {
console.error("An unknown error occurred", error);
}
}Open Source & Contributions
This project is open-source. Feel free to fork it, modify it, or contribute to its development.
Git Repository: https://github.com/g-obare13/pesapal-ts
git clone https://github.com/g-obare13/pesapal-ts.git
cd pesapal-ts
pnpm installFeatures
- Dependency-free: Pure TypeScript using native Fetch API.
- Edge Runtime compatible: Works on Cloudflare Workers, Vercel Edge, etc.
- Fully Typed: Catch errors at compile-time with complete type definitions.
- Rich Documentation: Comprehensive JSDoc comments for all methods and types.
- Sandbox & Production: Easy toggling between environments.
