pesapal-v3-node
v1.1.0
Published
A production-ready **Node.js / TypeScript SDK** for integrating with the Pesapal API 3.0.
Downloads
719
Readme
Pesapal Node.js SDK
A production-ready Node.js / TypeScript SDK for integrating with the Pesapal API 3.0.
This SDK provides a clean, typed, and extensible interface for handling payments, IPN (Instant Payment Notifications), and transaction status—designed with modern best practices like retries, logging, and modular architecture.
✨ Features
- ✅ Full TypeScript support (typed requests & responses)
- 🔐 Built-in automatic authentication with intelligent token caching
- 🔁 Automatic retries with exponential backoff for transient failures
- 🛡️ Client-side validation for orders and IPNs (fail-fast)
- 🧾 Structured resources (Orders, IPN)
- 🔌 IPN Security Utilities (Signature verification & parsing)
- 🪵 Pluggable logging hooks
- 🌍 Sandbox & Live environment support
- 🧪 Comprehensive test suite and CI/CD ready
- 📃 JSDoc on all methods
🔐 Security Note
[!WARNING] NEVER commit your
.envfile or hardcode live credentials in your source code. Always use environment variables to store yourconsumerKeyandconsumerSecret. Ensure.envis included in your.gitignorefile.
📦 Installation
npm install pesapal-v3-node🚀 Quick Start
import { Pesapal } from 'pesapal-v3-node';
const pesapal = new Pesapal({
consumerKey: process.env.PESAPAL_CONSUMER_KEY!,
consumerSecret: process.env.PESAPAL_CONSUMER_SECRET!,
environment: 'sandbox', // or 'live'
});
// 1. Register IPN URL (Optional if you already have an ipn_id)
const ipn = await pesapal.ipn.registerIPNUrl({
url: 'https://your-app.com/ipn',
ipn_notification_type: 'POST',
});
// 2. Submit an Order
const order = await pesapal.orders.submitOrder({
id: 'ORDER-001',
currency: 'UGX',
amount: 100.00,
description: 'Test payment',
callback_url: 'https://your-app.com/callback',
notification_id: ipn.ipn_id, // Use the ipn_id from step 1
billing_address: {
email_address: '[email protected]',
phone_number: '0700000000',
first_name: 'John',
last_name: 'Doe',
},
});
console.log('Redirect URL:', order.redirect_url);
// 3. Check Transaction Status
const status = await pesapal.orders.getStatus(order.order_tracking_id);
console.log('Status:', status.status);⚙️ Configuration
const pesapal = new Pesapal({
consumerKey: '...',
consumerSecret: '...',
environment: 'sandbox', // Default: sandbox
retries: 3, // Number of retries for transient failures (Default: 2)
timeoutMs: 10000, // Request timeout in milliseconds (Default: 10000)
logger: console, // Optional logger (debug, info, warn, error)
});📚 API Reference
Orders (pesapal.orders)
Submit Order
Initiates a transaction and returns a redirect URL. Includes client-side validation.
await pesapal.orders.submitOrder(payload: SubmitOrderRequest);Get Transaction Status
Checks the status of a transaction using its tracking ID.
await pesapal.orders.getStatus(orderTrackingId: string);IPN (pesapal.ipn)
Register IPN URL
Registers a URL to receive Instant Payment Notifications. Returns an ipn_id.
await pesapal.ipn.registerIPNUrl({
url: 'https://example.com/ipn',
ipn_notification_type: 'POST',
});Handle IPN Webhooks (Security)
The SDK provides helpers to securely parse and verify IPN notifications from Pesapal.
import { verifyIPNSignature, parseIPN } from 'pesapal-v3-node';
// In your webhook controller (e.g., Express)
app.post('/ipn', (req, res) => {
const rawBody = JSON.stringify(req.body);
const signature = req.headers['x-pesapal-signature']; // Placeholder header name
// 1. Verify it came from Pesapal
const isValid = verifyIPNSignature(signature, rawBody, process.env.PESAPAL_CONSUMER_SECRET);
if (isValid) {
// 2. Parse into a typed object
const ipnData = parseIPN(req.body);
console.log(`Update for Order: ${ipnData.OrderTrackingId}`);
}
res.sendStatus(200);
});🔁 Retries & Performance
Token Caching
The SDK automatically caches your authentication token and only requests a new one when the current one is near expiry. This eliminates unnecessary network round-trips.
Automatic Retries
The SDK automatically retries requests that fail due to network issues, 5xx errors, or rate limiting (429).
Normalised Errors
All errors are caught and thrown as PesapalError:
import { PesapalError } from 'pesapal-v3-node';
try {
await pesapal.orders.submitOrder(payload);
} catch (err) {
if (err instanceof PesapalError) {
console.error(`Error: ${err.message} (Code: ${err.code}, Status: ${err.status})`);
}
}🧪 Development & Testing
# Run tests
npm test
# Build project
npm run build
# Run full validation
npm run prepublishOnly📁 Project Structure
src/
index.ts # Main entry point & IPN utilities
client.ts # Core HTTP client with Auth integration
auth.ts # Authentication logic & token caching
orders.ts # Order resource with validation
ipn.ts # IPN resource with validation
errors.ts # Error normalization
helpers/
ipn.ts # IPN signature verification & parsing
retries.ts # Retry logic
types/
types.ts # TypeScript definitions📄 License
MIT License
