# Overview A unified, open-source payments SDK for Tanzania — one API, all providers. ## Quick Start ```bash pnpm add @borapesa/pesa @borapesa/clickpesa ``` ```ts import { createPesa } from '@borapesa/pesa'; import { ClickPesaProvider } from '@borapesa/clickpesa'; import { retryPlugin, loggingPlugin } from '@borapesa/pesa/plugins'; const pesa = createPesa({ provider: new ClickPesaProvider({ baseUrl: 'https://api.clickpesa.com', clientId: process.env.CLICKPESA_CLIENT_ID!, apiKey: process.env.CLICKPESA_API_KEY!, }), plugins: [ retryPlugin({ maxAttempts: 3 }), loggingPlugin({ level: 'info' }), ], }); // Initiate a payment const order = await pesa.createOrder({ amount: 15000, // TZS 15,000 currency: 'TZS', reference: 'order_abc123', customer: { name: 'Juma Ali', phone: '255712345678' }, }); // React to events pesa.on('PAYMENT_SUCCESS', async (event) => { await db.orders.update({ id: event.reference, status: 'paid', }); }); ``` ## Providers | Provider | Package | Auth | |---|---|---| | ClickPesa | `@borapesa/clickpesa` | Bearer token | | Selcom | `@borapesa/selcom` | HMAC-SHA256 | | AzamPay | `@borapesa/azampay` | Bearer token | | DPO | `@borapesa/dpo` | Planned | | Pesapal | `@borapesa/pesapal` | Planned | ## Mount on your server `pesa.mountWebhook` is a standard fetch handler — mount it anywhere: ```ts Bun.serve({ fetch: pesa.mountWebhook }); ``` See [Integrations](/docs/integrations) for one-liners across frameworks. --- # Getting Started Install Bora Pesa and process your first payment in under 5 minutes. Added in v0.1.0 ## Installation ```bash pnpm add @borapesa/pesa ``` The core package includes a [BogusProvider](/docs/api/pesa/classes/BasePaymentProvider) for local development — no credentials, no network, no sandbox registration. When you're ready for production, install a provider adapter: ```bash pnpm add @borapesa/clickpesa ``` ## Your first payment ```ts import { createPesa } from '@borapesa/pesa'; import { BogusPaymentProvider } from '@borapesa/pesa/testing'; // 1. Create an instance — that's it, no config needed for dev const pesa = createPesa({ provider: new BogusPaymentProvider({ defaultBehavior: 'success' }), }); // 2. Initiate a payment const order = await pesa.createOrder({ amount: 15000, // TZS 15,000 — whole integers only currency: 'TZS', reference: 'order_abc123', // Your internal order ID — must be unique customer: { name: 'Juma Ali', phone: '255712345678', // MSISDN format: 255XXXXXXXXX }, }); console.log(order.status); // 'SUCCESS' console.log(order.orderId); // Provider-assigned transaction ID ``` ## React to events Bora Pesa emits typed events after every verified webhook: ```ts pesa.on('PAYMENT_SUCCESS', async (event) => { // event.reference — your order ID // event.amount — TZS amount // event.provider — which provider processed it await db.orders.update({ where: { id: event.reference }, data: { status: 'paid' }, }); }); ``` ## Going to production Swap the BogusProvider for a real provider and add a persistent event store: ```bash pnpm add @borapesa/clickpesa @borapesa/sqlite ``` ```ts import { retryPlugin, idempotencyPlugin, loggingPlugin } from '@borapesa/pesa/plugins'; import { ClickPesaProvider } from '@borapesa/clickpesa'; import { SQLiteAdapter } from '@borapesa/sqlite'; const pesa = createPesa({ provider: new ClickPesaProvider({ clientId: process.env.CLICKPESA_CLIENT_ID!, apiKey: process.env.CLICKPESA_API_KEY!, checksumKey: process.env.CLICKPESA_CHECKSUM_KEY, // enables webhook verification }), db: new SQLiteAdapter('./pesa.db'), plugins: [ idempotencyPlugin(), retryPlugin({ maxAttempts: 3 }), loggingPlugin({ level: 'info' }), ], }); ``` Any class implementing [`PesaDatabaseAdapter`](/docs/api/pesa/interfaces/PesaDatabaseAdapter) works as an event store — use `@borapesa/sqlite`, or implement the four-method interface for your own database. See [Adapters](/docs/adapters) for details. ## Mount on your server Every `pesa` instance exposes a webhook handler. Mount it publicly — providers POST callbacks here: ```ts Bun.serve({ fetch: pesa.mountWebhook }); ``` The handler serves one endpoint (customizable via `basePath` in config): - `POST {basePath}/webhook` — receive provider callbacks For order creation and status queries, use `pesa.createOrder()` and `pesa.getPaymentStatus()` in your own routes behind your own auth middleware. `basePath` defaults to `/pesa`. ## Next steps - [Architecture](/docs/architecture) — understand the design - [Event System](/docs/events) — webhooks, persistence, and event handlers - [Plugins](/docs/plugins) — retry, idempotency, logging, and custom plugins - [Error Handling](/docs/errors) — the error hierarchy and when to retry - [API Reference](/docs/api) — auto-generated from JSDoc --- # Architecture How Bora Pesa is designed — factory pattern, provider abstraction, plugin pipeline, and event store. Added in v0.1.0 Bora Pesa is architecturally inspired by [better-auth](https://better-auth.com). A single factory function wires together a payment provider, plugins, and an event store into a fully configured instance. ## The factory [`createPesa()`](/docs/api/pesa/functions/createPesa) is the only entry point. It takes a config object and returns a [`PesaInstance`](/docs/api/pesa/interfaces/PesaInstance): ``` createPesa({ provider, plugins?, db?, basePath? }) │ ▼ ┌─────────────────────────────────┐ │ PesaInstance │ │ │ │ .createOrder(payload) │ │ .getPaymentStatus(orderId) │ │ .disburse(payload) │ │ .handleWebhook(body, headers) │ │ .on(event, handler) │ │ .mountWebhook │ └─────────────────────────────────┘ ``` ## Provider abstraction Every payment provider implements [`BasePaymentProvider`](/docs/api/pesa/classes/BasePaymentProvider) — an abstract class with four required methods: | Method | Purpose | | ------------------------------ | ------------------------------------------ | | `createOrder(payload)` | Initiate a checkout / USSD push / redirect | | `getPaymentStatus(orderId)` | Poll or fetch current status | | `handleWebhook(body, headers)` | Parse + verify an incoming webhook | | `disburse(payload)` | B2C / wallet-out disbursement | Eight optional methods cover previews, refunds, cancellations, balance queries, name lookups, credential validation, and order listing. Providers override what they support; the rest throw `PesaUnsupportedError`. On the returned `PesaInstance`, unsupported operations are `undefined` — use feature detection (`if (pesa.refund)`) rather than catching `PesaUnsupportedError`. **Application code never imports provider-specific logic.** Swap Selcom for ClickPesa with a one-line config change. The SDK calls only `BasePaymentProvider` methods — no provider internals ever leak. ## Plugin pipeline Plugins intercept provider requests and webhook events at specific lifecycle points: ``` app calls pesa.createOrder(payload) ├─ 1. validateCreateOrderPayload() ← SDK-level input validation ├─ 2. beforeRequest hooks (once) ← idempotency, logging ├─ 3. for attempt in retryPlugin maxAttempts: │ ├─ provider.createOrder() │ └─ afterResponse hooks ← retry decision, logging └─ returns result (or throws after safety cap: 100) webhook arrives: ├─ 1. Provider verifies signature ├─ 2. SDK assigns UUID ├─ 3. Plugin onPaymentEvent hooks ← webhook verification, logging ├─ 4. Event persisted to store └─ 5. pesa.on() handlers fire ``` Plugins are composed **in order** in the `plugins` array. Order matters — place `idempotencyPlugin` before `retryPlugin`. ## Event store Every verified webhook is normalized into a [`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent) and persisted. This is the **source of truth** for all payment activity. The default adapter is in-memory (lost on restart). Swap to a persistent adapter for production: ```ts import { SQLiteAdapter } from '@borapesa/sqlite'; const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), db: new SQLiteAdapter('./pesa.db'), }); ``` For other storage backends, implement the [`PesaDatabaseAdapter`](/docs/api/pesa/interfaces/PesaDatabaseAdapter) interface — four methods (`saveEvent`, `getEvent`, `getEventsByReference`, `getEventsByOrderId`) that work with any database. See the [`@borapesa/sqlite`](/docs/api/sqlite) source for the reference implementation. ## HTTP mount `pesa.mountWebhook` is a standard fetch handler — a `(Request) => Promise` function. Mount it on any fetch-compatible server with no adapter needed: ``` ┌──────────────────────┐ │ │ Bun.serve() ──┤ pesa.mountWebhook ├── POST /pesa/webhook │ (webhook only) │ │ │ └──────────────────────┘ ``` ```ts // Bun, Deno, Cloudflare Workers, Node 18+ Bun.serve({ fetch: pesa.mountWebhook }); // Elysia new Elysia().mount(pesa.mountWebhook); // Hono new Hono().mount('/pesa', pesa.mountWebhook); // Next.js App Router export const POST = pesa.mountWebhook; ``` The route prefix defaults to `/pesa` and is configurable via `basePath` in [`PesaConfig`](/docs/api/pesa/interfaces/PesaConfig). ## Design decisions These are locked for v1.0 and should not change without an RFC: | Decision | Rationale | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | **TZS only, whole integers** | TZS has no subunits in digital payments. `15000` = TZS 15,000. Floats are a bug surface. | | **MSISDN phone format** | `255XXXXXXXXX`. Local `07XX` rejected at validation. Matches every Tanzanian payment API. | | **Auth out of scope** | Pesa is payment infrastructure. Use better-auth or your own auth system. | | **Secrets never reach the client** | The SDK is server-only — all provider API calls happen server-side. No credentials are ever exposed to the browser. | | **AMBIGUOUS is a first-class status** | Selcom returns this when the transaction outcome is unknown. Normalizing it to `PENDING` or `FAILED` would lose information. Applications should poll. | --- # Providers Available payment providers — Selcom, ClickPesa, AzamPay, Snippe — and their capabilities. Added in v0.1.0 Providers are the bridge between the SDK and payment gateways. Pick one that matches your business needs. Swap providers with a one-line config change — no application code changes needed. ## Comparison A ✅ means the feature is implemented in our provider adapter. A `—` does not guarantee the upstream provider API lacks the feature — it may simply not be wired up yet. Open an issue if you need it. | | Selcom | ClickPesa | AzamPay | Snippe | | --------------------- | ---------------- | ------------ | ------------ | ------------ | | MNO USSD push | ✅ | ✅ | ✅ | ✅ | | MNO redirect checkout | ✅ | ✅ | — | — | | Card payment | — | ✅ | — | ✅ | | Bank checkout (OTP) | — | — | ✅ | — | | Hosted payment page | — | ✅ | ✅ | ✅ | | Disburse (wallet) | ✅ | ✅ | ✅ | ✅ | | Disburse (bank) | ✅ | ✅ | — | ✅ | | Webhook signature | HMAC-SHA256 | HMAC-SHA256 | RSA-PKCS#1 | HMAC-SHA256 | | Order cancellation | ✅ | — | — | — | | Order listing | ✅ | — | — | ✅ | | Balance query | ✅ | — | — | ✅ | | Name lookup | ✅ | ✅ | ✅ | — | | Credential validation | ✅ | ✅ | ✅ | ✅ | | Auth method | HMAC per-request | Bearer token | Bearer token | Bearer token | | Payout fee preview | — | ✅ | — | — | ## Configuration Each provider has a different config surface — fields match what each provider's dashboard gives you. Every config accepts an optional `baseUrl` override (or equivalent) for sandbox/proxy use. ### ClickPesa ```ts import { ClickPesaProvider } from '@borapesa/clickpesa' ``` | Field | Required | Description | | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `clientId` | ✅ | Client ID from ClickPesa dashboard | | `apiKey` | ✅ | API key from ClickPesa dashboard | | `checksumKey` | | HMAC-SHA256 signing key for webhook verification. Generate in the ClickPesa dashboard. When set, all POST/PUT/PATCH bodies are signed and incoming webhooks are verified. **Without it, webhooks are accepted unverified.** | | `sandbox` | | `true` → `https://api-sandbox.clickpesa.com`. `false` (default) → `https://api.clickpesa.com`. | | `baseUrl` | | Explicit base URL override — takes precedence over `sandbox`. | | `redirectUrl` | | Default redirect URL for hosted checkout. Overridable per-payment via `payload.redirectUrl`. | ```ts const pesa = createPesa({ provider: new ClickPesaProvider({ clientId: process.env.CLICKPESA_CLIENT_ID!, apiKey: process.env.CLICKPESA_API_KEY!, sandbox: false, redirectUrl: 'https://mysite.com/success', }), }) ``` ### Selcom ```ts import { SelcomPaymentProvider } from '@borapesa/selcom' ``` | Field | Required | Description | | --------------- | -------- | --------------------------------------------------------------------------------- | | `apiKey` | ✅ | API key from Selcom | | `apiSecret` | ✅ | API secret for HMAC-SHA256 signing | | `vendor` | ✅ | Float account / vendor identifier | | `pin` | ✅ | Float account PIN — required for disbursement and balance queries | | `baseUrl` | | Defaults to `https://apigw.selcommobile.com`. Set to the sandbox URL for testing. | | `senderAccount` | | Source account number for Qwiksend bank transfers. Defaults to `vendor`. | | `senderName` | | Account holder display name for bank transfers. Defaults to `vendor`. | | `senderPhone` | | Sender mobile number for bank transfers. | | `redirectUrl` | | Default redirect URL for checkout orders. Overridable per-payment via `payload.redirectUrl`. | | `cancelUrl` | | Cancel URL for checkout orders. Customer is sent here if they abandon payment. | | `webhookUrl` | | Webhook callback URL for payment status. Typically `pesa.mountWebhook` endpoint. | ```ts const pesa = createPesa({ provider: new SelcomPaymentProvider({ apiKey: process.env.SELCOM_API_KEY!, apiSecret: process.env.SELCOM_API_SECRET!, vendor: process.env.SELCOM_VENDOR!, pin: process.env.SELCOM_PIN!, redirectUrl: 'https://mysite.com/return', }), }) ``` ### AzamPay ```ts import { AzamPayPaymentProvider } from '@borapesa/azampay' ``` | Field | Required | Description | | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `appName` | ✅ | App name from AzamPay dashboard | | `clientId` | ✅ | Client ID from AzamPay dashboard | | `clientSecret` | ✅ | Client secret from AzamPay dashboard | | `apiKey` | ✅ | API key from AzamPay dashboard | | `senderName` | ✅ | Merchant display name for disbursement transfers | | `senderBank` | | Merchant bank name for disbursement. Defaults to `"AzamPay"`. | | `sandbox` | | Target sandbox (default: `true`). | | `authBaseUrl` | | Override auth base URL. | | `checkoutBaseUrl` | | Override checkout base URL. | | `disbursementBaseUrl` | | Override disbursement base URL. **AzamPay uses separate hosts** for checkout and disbursement — this defaults automatically per `sandbox`. | ```ts const pesa = createPesa({ provider: new AzamPayPaymentProvider({ appName: process.env.AZAMPAY_APP_NAME!, clientId: process.env.AZAMPAY_CLIENT_ID!, clientSecret: process.env.AZAMPAY_CLIENT_SECRET!, apiKey: process.env.AZAMPAY_API_KEY!, senderName: process.env.AZAMPAY_SENDER_NAME!, sandbox: false, }), }) ``` ### Snippe ```ts import { SnippePaymentProvider } from '@borapesa/snippe' ``` | Field | Required | Description | | --------------- | -------- | -------------------------------------------------------------------------------------------------------- | | `apiKey` | ✅ | Snippe API key (`snp_...`) from the Snippe dashboard | | `webhookSecret` | ✅ | HMAC-SHA256 signing key for webhook verification. Found in Snippe dashboard → Settings → Webhook Secret. | | `baseUrl` | | Defaults to `https://api.snippe.sh`. Override for proxies or staging. | | `webhookUrl` | | Default webhook URL set on create/disburse calls. Provider callbacks POST here. | | `redirectUrl` | | Default redirect URL for card payments. Overridable per-payment via `payload.redirectUrl`. | | `cancelUrl` | | Cancel URL for card payments. Falls back to `redirectUrl` if not set. | | `timeoutMs` | | Request timeout in milliseconds (default: 30_000). | ```ts const pesa = createPesa({ provider: new SnippePaymentProvider({ apiKey: process.env.SNIPPE_API_KEY!, webhookSecret: process.env.SNIPPE_WEBHOOK_SECRET!, webhookUrl: 'https://mysite.com/pesa/webhook', redirectUrl: 'https://mysite.com/success', cancelUrl: 'https://mysite.com/cancelled', }), }) ``` ## Provider-specific features Some providers expose methods beyond the standard `BasePaymentProvider` interface. These are available on the provider instance directly (`pesa.provider`) but are **not** part of the unified `PesaInstance` API. ### Selcom - **Bank disbursement (Qwiksend)** — send to bank accounts via `senderAccount`, `senderName`, `senderPhone` config. - **Order management** — `cancelOrder()`, `listOrders()` are first-class. - **Wallet pull payment** — `checkoutWalletPayment()` triggers USSD from an existing checkout order for in-app payments. - **Utility payments** — `payUtility()`, `lookupUtility()`, `queryUtilityStatus()` for LUKU, DSTV, GEPG, airtime, and more. - **Selcom Pesa** — `selcomPesaCashin()`, `selcomPesaNameLookup()` for Selcom's mobile wallet. - **Agent cashout** — `agentCashout()` sends funds for cash pickup at Huduma agents via `*150*50#`. - **Stored cards** — `fetchStoredCards()`, `deleteStoredCard()` for tokenized card management. ### ClickPesa - **BillPay** — 7 methods for control number generation, customer management, and payment status. - **Payout links** — `generatePayoutLink()` for shareable disbursement URLs. - **Exchange rates** — `getExchangeRates()` for currency conversion. - **Bank listing** — `getBanks()` for supported bank codes. - **Account statements** — `getAccountStatement()` for reconciliation. ### AzamPay - **Bank checkout** — OTP-based bank payment flow (CRDB, NMB). - **Payment partners** — `getPaymentPartners()` to list available MNO partners. - **RSA callback verification** — callbacks are signed with RSA-SHA256; the SDK verifies them automatically. - **Disbursement routing** — separate base URL for disbursement endpoints (`disbursementBaseUrl` config). - **Provider tracking** — `raw._providerName` and `raw._checkoutProvider` on order results for status queries. ### Snippe - **Card payments** — `createOrder` with `redirectUrl` (config or payload) routes to Snippe's card endpoint (Visa/Mastercard). Returns `checkoutUrl` for the payment page. - **Hosted checkout sessions** — `createCheckoutSession()` / `getCheckoutSession()` / `listCheckoutSessions()` / `cancelCheckoutSession()` provider-specific methods for Snippe's hosted payment page. Returns `checkoutUrl` + `paymentLinkUrl` for sharing via SMS/WhatsApp. - **USSD push retrigger** — `retriggerPush(reference)` re-sends the PIN prompt for a pending mobile payment. - **Payout fee preview** — `previewDisburse()` returns the transaction fee before committing a payout. - **Search** — `listOrders()` accepts optional Snippe-specific filters: `status`, `paymentType`, and free-text `q`. - **Payout failure reason** — `raw.failure_reason` on failed disbursements for debugging. - **HMAC webhook verification** — signature verification with replay protection (5-minute window). ## Writing a provider Every provider extends [`BasePaymentProvider`](/docs/api/pesa/classes/BasePaymentProvider). Four methods are required, eight are optional. ```ts import { BasePaymentProvider } from '@borapesa/pesa' class MyProvider extends BasePaymentProvider { readonly name = 'my-provider' // Required async createOrder(payload) { /* ... */ } async getPaymentStatus(orderId) { /* ... */ } async handleWebhook(body, headers) { /* ... */ } async disburse(payload) { /* ... */ } // Optional — override what you support async getNameLookup(phoneOrAccount) { /* ... */ } } ``` See the [Architecture](/docs/architecture) page for the full provider lifecycle. --- # Adapters Database adapters for the event store — SQLite, in-memory, and custom. Added in v0.1.0 Adapters persist [`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent) entries to the event store. The default is in-memory (lost on restart) — swap to a persistent adapter for production. ## Comparison | | Memory (default) | SQLite | Custom / Bring-your-own | | ------------------- | ---------------- | ----------------- | ----------------------- | | Persists on restart | ❌ | ✅ | Depends on your impl | | Zero dependencies | ✅ | ❌ (better-sqlite3) | Depends | | Dev / CI ready | ✅ | ✅ | — | | Production ready | ❌ | ✅ | ✅ | ## Available adapters ### SQLite (`@borapesa/sqlite`) Zero-config persistent storage powered by [better-sqlite3](https://github.com/WiseLibs/better-sqlite3). The database file is created automatically at the given path. ```bash pnpm add @borapesa/sqlite ``` ```ts import { SQLiteAdapter } from '@borapesa/sqlite'; const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), db: new SQLiteAdapter('./pesa.db'), }); ``` WAL mode is enabled by default for concurrent read/write performance. See the [`@borapesa/sqlite` API docs](/docs/api/sqlite) for full details. `@borapesa/sqlite` is the only adapter package provided. For other databases, implement the interface yourself — the [`SQLiteAdapter` source](https://github.com/borapesa/pesa/blob/master/adapters/sqlite/src/index.ts) is the reference. ## Writing your own Implement [`PesaDatabaseAdapter`](/docs/api/pesa/interfaces/PesaDatabaseAdapter) — four methods: ```ts import type { PesaDatabaseAdapter, PaymentEvent } from '@borapesa/pesa'; class MyAdapter implements PesaDatabaseAdapter { async saveEvent(event: PaymentEvent): Promise { // Persist a verified PaymentEvent } async getEvent(id: string): Promise { // Retrieve a single event by UUID } async getEventsByReference(reference: string): Promise { // Retrieve all events for a merchant reference } async getEventsByOrderId(orderId: string): Promise { // Retrieve all events for a provider order ID } } ``` Pass your adapter via the `db` field in [`PesaConfig`](/docs/api/pesa/interfaces/PesaConfig): ```ts const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), db: new MyAdapter(), }); ``` See the [Architecture](/docs/architecture#event-store) page for how the event store fits into the webhook lifecycle. --- # Integrations Mount pesa.mountWebhook on any server or framework — one-liners for all major runtimes. `pesa.mountWebhook` is a standard fetch handler — a `(Request) => Promise` function. Mount it anywhere with no framework-specific package needed. ## Bun ```ts Bun.serve({ fetch: pesa.mountWebhook }); ``` ## Node (native http) ```ts import { createServer } from 'node:http'; const server = createServer(async (req, res) => { const webRequest = new Request(`http://${req.headers.host}${req.url}`, { method: req.method, headers: req.headers as Record, body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined, }); const webResponse = await pesa.mountWebhook(webRequest); res.writeHead(webResponse.status, Object.fromEntries(webResponse.headers)); res.end(await webResponse.text()); }); server.listen(3000); ``` ## Deno ```ts Deno.serve(pesa.mountWebhook); ``` ## Elysia ```ts new Elysia().mount(pesa.mountWebhook); ``` ## Hono ```ts new Hono().mount('/pesa', pesa.mountWebhook); ``` ## Next.js (App Router) ```ts // app/pesa/webhook/route.ts export const POST = pesa.mountWebhook; ``` ## SvelteKit ```ts // src/routes/pesa/webhook/+server.ts export const POST = ({ request }) => pesa.mountWebhook(request); ``` ## Express ```ts app.post('/pesa/webhook', async (req, res) => { const webResponse = await pesa.mountWebhook( new Request('https:///pesa/webhook', { method: 'POST', headers: req.headers as Record, body: JSON.stringify(req.body), }), ); res.status(webResponse.status).send(await webResponse.text()); }); ``` ## Fastify ```ts fastify.post('/pesa/webhook', async (request, reply) => { const webResponse = await pesa.mountWebhook( new Request('https:///pesa/webhook', { method: 'POST', headers: request.headers as Record, body: JSON.stringify(request.body), }), ); reply.status(webResponse.status).send(await webResponse.text()); }); ``` ## NestJS ```ts @Controller('pesa') class PesaController { @Post('webhook') async webhook(@Req() req: Request) { return pesa.mountWebhook(req); } } ``` ## TanStack Start ```ts // app/routes/pesa/webhook.ts export const action = async ({ request }: { request: Request }) => { return pesa.mountWebhook(request); }; ``` ## Cloudflare Workers ```ts export default { async fetch(request: Request) { return pesa.mountWebhook(request); }, }; ``` ## Astro ```ts // src/pages/pesa/webhook.ts export const POST = ({ request }: { request: Request }) => pesa.mountWebhook(request); ``` --- The route prefix defaults to `/pesa` and is configurable via `basePath` in [`PesaConfig`](/docs/api/pesa/interfaces/PesaConfig). For order creation and status queries, use `pesa.createOrder()` and `pesa.getPaymentStatus()` in your own routes behind your own auth middleware. --- # Event System Webhooks, event persistence, and typed event handlers in Bora Pesa. Added in v0.1.0 Every verified webhook is normalized into a [`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent), persisted to the event store, and emitted to registered handlers. This is the **source of truth** for all payment activity in your application. ## The lifecycle ``` Provider sends webhook → POST /api/pesa/webhook 1. Provider adapter verifies cryptographic signature (HMAC, checksum, etc.) 2. SDK assigns a UUID to the event 3. Plugin onPaymentEvent hooks run (webhook verification, logging) 4. Event is persisted to the event store 5. pesa.on() handlers fire — in registration order ``` Events are **persisted before handlers fire**. If your handler crashes, the event is already in the database — you can safely retry without double-processing. ## PaymentEvent ```ts interface PaymentEvent { id: string; // UUID — generated by SDK type: PaymentEventType; // PAYMENT_SUCCESS | PAYMENT_FAILED | ... orderId: string; // Provider transaction ID reference: string; // Your order ID, echoed back amount: number; // TZS — whole integer currency: 'TZS'; status: PaymentStatus; // SUCCESS | FAILED | PENDING | ... provider: ProviderName; // clickpesa | selcom | ... timestamp: Date; metadata?: Record; raw?: unknown; // Original webhook payload } ``` ## Event types ```ts type PaymentEventType = | 'PAYMENT_SUCCESS' // Payment completed | 'PAYMENT_FAILED' // Payment failed | 'PAYMENT_PENDING' // Payment initiated, awaiting result | 'DISBURSEMENT_SUCCESS' // Payout sent | 'DISBURSEMENT_FAILED'; // Payout failed ``` ## Registering handlers Use `pesa.on()` to react to events. Handlers can be async — errors in one handler don't prevent others from firing. ```ts // Single handler pesa.on('PAYMENT_SUCCESS', async (event) => { await db.orders.update({ where: { id: event.reference }, data: { status: 'paid' }, }); }); // Multiple handlers for the same event type pesa.on('PAYMENT_SUCCESS', (event) => { console.log(`Payment ${event.reference}: TZS ${event.amount}`); }); pesa.on('PAYMENT_SUCCESS', async (event) => { await emailService.sendReceipt(event.reference); }); // React to payment failures pesa.on('PAYMENT_FAILED', async (event) => { await notifications.notifySupport(event); }); // Monitor disbursements pesa.on('DISBURSEMENT_SUCCESS', (event) => { console.log(`Payout ${event.reference} sent via ${event.provider}`); }); ``` ## Plugin onPaymentEvent hooks Plugins also have `onPaymentEvent` hooks that fire **before** user-registered handlers. Plugins fire in registration order; user handlers fire after all plugin hooks complete. ```ts const auditPlugin: PesaPlugin = { name: 'audit-log', async onPaymentEvent(event) { console.log(`[audit] ${event.type} for order ${event.orderId}`); }, }; ``` Webhook secret enforcement (`BORAPESA_WEBHOOK_SECRET`) is built into `createPesa()` — no plugin needed. ## Querying past events The event store supports querying by ID, reference, or order ID: ```ts // Via PesaDatabaseAdapter (if you have access to the adapter) const events = await db.getEventsByReference('order_abc123'); const event = await db.getEvent('uuid-here'); ``` For most use cases, `pesa.on()` handlers combined with your own database are simpler — store what you need in your schema when the handler fires. --- # Plugins Retry, idempotency, logging, and writing custom plugins. Added in v0.1.0 Plugins intercept requests and webhook events at specific points in the lifecycle. They are plain objects passed in the `plugins` array of `PesaConfig`. **Order matters** — plugins are composed in sequence. ```ts import { createPesa } from '@borapesa/pesa'; import { retryPlugin, idempotencyPlugin, loggingPlugin } from '@borapesa/pesa/plugins'; const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), plugins: [ idempotencyPlugin(), // must be before retryPlugin retryPlugin({ maxAttempts: 3 }), loggingPlugin({ level: 'info' }), ], }); ``` ## Built-in plugins ### `retryPlugin()` Retries payments on in-progress statuses (`AMBIGUOUS`, `PROCESSING`, `QUEUED`) with configurable backoff. ```ts retryPlugin({ maxAttempts: 3, // default: 3 backoff: 'exponential', // 'exponential' | 'linear' | 'fixed' baseDelayMs: 1000, // default: 1000 }) ``` | Backoff | Formula | Delay sequence (base=1000) | |---|---|---| | `exponential` | `base * 2^attempt` | 1s, 2s, 4s | | `linear` | `base * (attempt + 1)` | 1s, 2s, 3s | | `fixed` | `base` | 1s, 1s, 1s | ### `idempotencyPlugin()` Prevents duplicate charges on network retries. Keys on `operation + reference` — the same reference sent to the same operation twice throws an error. ```ts idempotencyPlugin(); // in-memory set, persistent store planned for v1.0 ``` Place this **before** `retryPlugin` in the array. The retry loop in `createPesa` won't re-run `beforeRequest` hooks on retries, so idempotency checks only fire once per logical request. ### `loggingPlugin()` Structured logs for all SDK operations. Redacts phone numbers and email addresses from payloads. ```ts loggingPlugin({ level: 'info', // 'debug' | 'info' | 'warn' | 'error' logger: console, // swap for Pino, Winston, etc. }) ``` Logs include: operation name, status, duration in ms, and sanitized payload. ## Devtools The [`@borapesa/devtools`](/docs/api/devtools) package provides developer utilities. ### `tunnelPlugin()` Starts a Cloudflare Quick Tunnel for local webhook development. Requires [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) on the system PATH (free, no account needed). ```bash pnpm add -D @borapesa/devtools ``` ```ts import { tunnelPlugin } from '@borapesa/devtools'; const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), plugins: [ ...(process.env.NODE_ENV !== 'production' ? [tunnelPlugin({ port: 8080 })] : []), ], }); ``` ```ts tunnelPlugin({ port: 3000, // local port to expose (default: 3000) log: true, // print the tunnel URL to console (default: true) webhookPath: '/pesa/webhook', // path shown in the banner (default: '/pesa/webhook') binary: 'cloudflared', // override for testing with mock binaries }) ``` On startup, it prints the public webhook URL: ``` 🛜 @borapesa/devtools Tunnel ready: https://cool-fox.trycloudflare.com Webhook URL: https://cool-fox.trycloudflare.com/pesa/webhook ``` This is for **local development only**. Guard it behind `NODE_ENV !== 'production'`. Do not use it in production — webhooks should go directly to your deployed server. ## Plugin interface Write custom plugins by implementing the [`PesaPlugin`](/docs/api/pesa/interfaces/PesaPlugin) interface: ```ts interface PesaPlugin { name: string; // Intercept outgoing request beforeRequest?: (ctx: RequestContext) => Promise; // Intercept provider response — set ctx.retry = true to trigger retry afterResponse?: (ctx: ResponseContext) => Promise; // React to verified, about-to-be-persisted events onPaymentEvent?: (event: PaymentEvent) => Promise; // Called once at startup with the assembled PesaInstance init?: (pesa: PesaInstance) => void; } ``` ## Example: SMS notification plugin ```ts const smsPlugin: PesaPlugin = { name: 'sms-notify', async onPaymentEvent(event) { if (event.type !== 'PAYMENT_SUCCESS') return; await fetch('https://sms-gateway.example.com/send', { method: 'POST', body: JSON.stringify({ phone: event.metadata?.customerPhone, message: `Payment of TZS ${event.amount} confirmed. Ref: ${event.reference}`, }), }); }, }; const pesa = createPesa({ provider: new ClickPesaProvider({ ... }), plugins: [smsPlugin, retryPlugin()], }); ``` --- # Testing BogusPaymentProvider — a deterministic test double for local development and integration tests. Added in v0.1.0 `BogusPaymentProvider` is a test double that implements every `BasePaymentProvider` method — no API keys, no network calls. Perfect for local development, CI, and integration tests. ```ts import { createPesa } from '@borapesa/pesa'; import { BogusPaymentProvider } from '@borapesa/pesa/testing'; const pesa = createPesa({ provider: new BogusPaymentProvider(), }); ``` ## Configuration ```ts new BogusPaymentProvider({ defaultBehavior: 'success', // 'success' | 'failure' | 'pending' delay: 200, // simulated network delay in ms (default: 0) }) ``` | Option | Type | Default | Description | |--------|------|---------|-------------| | `defaultBehavior` | `'success' \| 'failure' \| 'pending'` | `'success'` | Default outcome for all operations | | `delay` | `number` | `0` | Simulated network latency in milliseconds | ## Scripted behaviors Override the default behavior per-reference for more realistic tests: ```ts const provider = new BogusPaymentProvider({ defaultBehavior: 'success', }); // Script specific outcomes by reference provider.script([ { reference: 'order_fail', behavior: 'failure' }, { reference: 'order_pending', behavior: 'pending' }, { reference: 'order_after3', behavior: 'success', after: 3 }, // succeeds on 4th call ]); ``` The `after` option simulates flaky endpoints — the first N calls return the default, the N+1th returns the scripted behavior. ## Example: integration test ```ts import { describe, it, expect } from 'vitest'; import { createPesa } from '@borapesa/pesa'; import { BogusPaymentProvider } from '@borapesa/pesa/testing'; describe('checkout flow', () => { it('creates a successful order', async () => { const pesa = createPesa({ provider: new BogusPaymentProvider({ defaultBehavior: 'success' }), }); const order = await pesa.createOrder({ amount: 15000, currency: 'TZS', reference: 'test_001', customer: { name: 'Juma', phone: '255712345678' }, }); expect(order.status).toBe('PENDING'); expect(order.orderId).toBeDefined(); }); it('handles payment failure', async () => { const provider = new BogusPaymentProvider({ defaultBehavior: 'success' }); provider.script([{ reference: 'bad_card', behavior: 'failure' }]); const pesa = createPesa({ provider }); const order = await pesa.createOrder({ amount: 15000, currency: 'TZS', reference: 'bad_card', customer: { name: 'Juma', phone: '255712345678' }, }); expect(order.status).toBe('FAILED'); }); }); ``` ## Supported operations `BogusPaymentProvider` implements all eight optional methods: - `refund()` / `cancelOrder()` — return success for existing orders - `getBalance()` — returns a fake 1,000,000 TZS balance - `previewOrder()` / `previewDisburse()` — return mock fee estimates - `getNameLookup()` — returns `{ found: true, accountName: '...' }` - `listOrders()` — returns all orders created by this provider instance - `validateCredentials()` — returns `{ valid: true }` --- # Error Handling Understanding PesaError, when to retry, and how to handle provider errors. Added in v0.1.0 All errors thrown by Bora Pesa extend [`PesaError`](/docs/api/pesa/classes/PesaError). Use `instanceof` checks to handle specific error types. ## Error hierarchy ``` PesaError (base) ├── PesaValidationError ← Bad input (amount ≤ 0, invalid phone, empty reference) ├── PesaNetworkError ← Provider unreachable (DNS, timeout, connection refused) ├── PesaProviderError ← Provider returned an error (HTTP 4xx/5xx, API error) ├── PesaWebhookError ← Webhook signature verification failed └── PesaUnsupportedError ← Provider doesn't implement this optional operation ``` Every error has a `code` property for programmatic handling without `instanceof`: | Error class | `code` | | ----------------------- | ------------------- | | `PesaValidationError` | `VALIDATION_ERROR` | | `PesaNetworkError` | `NETWORK_ERROR` | | `PesaProviderError` | `PROVIDER_ERROR` | | `PesaWebhookError` | `WEBHOOK_ERROR` | | `PesaUnsupportedError` | `UNSUPPORTED` | ## Handling errors ```ts import { PesaValidationError, PesaNetworkError, PesaProviderError } from '@borapesa/pesa'; try { const order = await pesa.createOrder({ amount: 15000, currency: 'TZS', reference: 'order_001', customer: { name: 'Juma', phone: '255712345678' }, }); } catch (err) { if (err instanceof PesaValidationError) { // Bad input — fix the payload. Don't retry. console.error('Invalid payload:', err.message); return { error: err.message }; } else if (err instanceof PesaNetworkError) { // Provider unreachable — retry with backoff console.error('Network error:', err.message); await scheduleRetry('order_001'); } else if (err instanceof PesaProviderError) { // Provider returned an error — check status code if (err.statusCode >= 500) { // Server error — retry await scheduleRetry('order_001'); } else { // Client error — don't retry console.error('Provider rejected request:', err.message); } } } ``` ## When to retry | Error | Retry? | Reason | |---|---|---| | `PesaNetworkError` | ✅ Yes | Transient — network will recover | | `PesaProviderError` (5xx) | ✅ Yes | Provider is temporarily down | | `PesaProviderError` (4xx) | ❌ No | Bad credentials, invalid request — retrying won't help | | `PesaValidationError` | ❌ No | Fix the payload before resending | | `PesaWebhookError` | ❌ No | Invalid signature — likely a forged webhook | | `PesaUnsupportedError` | ❌ No | Provider doesn't support this operation — use feature detection | ## Feature detection Some operations are optional — not all providers support refunds, previews, or cancellations. On the `PesaInstance`, unsupported operations are `undefined`. Check before calling: ```ts // All optional operations support feature detection: if (pesa.refund) await pesa.refund('order_123', 5000); if (pesa.cancelOrder) await pesa.cancelOrder('order_123'); if (pesa.previewOrder) await pesa.previewOrder({ ... }); if (pesa.previewDisburse) await pesa.previewDisburse({ ... }); if (pesa.getBalance) await pesa.getBalance(); if (pesa.getNameLookup) await pesa.getNameLookup('255712345678'); if (pesa.validateCredentials) await pesa.validateCredentials(); if (pesa.listOrders) await pesa.listOrders({ fromDate: new Date('2026-01-01') }); ``` Calling an undefined operation throws `TypeError`, not `PesaUnsupportedError`. The provider-level default implementations throw `PesaUnsupportedError`, but `createPesa()` binds only supported methods — everything else is left `undefined`. --- # AI Tools MCP server, llms.txt, and markdown endpoints that let AI agents read, search, and integrate Bora Pesa. Bora Pesa is built to be integrated by AI coding agents as well as humans. Three complementary surfaces expose the same documentation: 1. **MCP server** (`@borapesa/mcp`): searchable docs, provider registry, and code examples inside your agent 2. **llms.txt endpoints**: the whole site as plain markdown over HTTPS 3. **AGENTS.md**: contributor conventions for agents working inside the repository ## MCP server The [Model Context Protocol](https://modelcontextprotocol.io) server ships the full documentation snapshot inside the package, so it works offline and stays versioned with each release. Once connected, your agent can answer provider questions, look up config fields, and pull runnable examples while it writes your integration. ### Tools | Tool | What it does | | ---------------- | ----------------------------------------------------------------------------- | | `search_docs` | Keyword search across all guides and API reference pages | | `get_doc` | Read any docs page as markdown | | `list_docs` | List every page with title and description | | `list_providers` | Compare Selcom, AzamPay, ClickPesa, Snippe, and the Bogus test provider | | `get_provider` | Config fields, capabilities, and webhook verification notes for one provider | | `get_example` | Runnable TypeScript for quickstart, webhooks, events, disbursement, and more | Every docs page is also exposed as an MCP resource under `borapesa://docs/`. ### Claude Code ```bash claude mcp add borapesa -- npx -y @borapesa/mcp ``` Or check a `.mcp.json` into your project root so every contributor's agent picks it up: ```json { "mcpServers": { "borapesa": { "command": "npx", "args": ["-y", "@borapesa/mcp"] } } } ``` ### Cursor Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project): ```json { "mcpServers": { "borapesa": { "command": "npx", "args": ["-y", "@borapesa/mcp"] } } } ``` ### VS Code (GitHub Copilot) Add to `.vscode/mcp.json`: ```json { "servers": { "borapesa": { "command": "npx", "args": ["-y", "@borapesa/mcp"] } } } ``` ### Windsurf Add to `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "borapesa": { "command": "npx", "args": ["-y", "@borapesa/mcp"] } } } ``` The server runs locally over stdio and makes no network calls. It bundles the docs that shipped with its release, so pin the package version if you want docs matching an older SDK version. ## llms.txt endpoints For agents that fetch over HTTPS instead of MCP, the site follows the [llms.txt convention](https://llmstxt.org): | URL | Contents | | ------------------------------------------ | ------------------------------------------------- | | [`/llms.txt`](/llms.txt) | Index of every page with absolute markdown links | | [`/llms-full.txt`](/llms-full.txt) | The entire documentation in a single file | | `/llms//index.md` | Any single page as markdown | Examples: ```text https://borapesa.dev/llms/getting-started/index.md https://borapesa.dev/llms/errors/index.md https://borapesa.dev/llms/api/pesa/functions/createPesa/index.md ``` Every docs page also has a copy-as-markdown button in its header, and the same content is linked for crawlers via `robots.txt` and `sitemap.xml`. ## AGENTS.md The repository root carries an [`AGENTS.md`](https://github.com/borapesa/pesa/blob/master/AGENTS.md) with the conventions agents must follow when contributing: whole-integer TZS amounts, MSISDN phone validation, extensionless imports, Biome formatting, and the test coverage bar. If you point a coding agent at the repo, it reads this file automatically. ## Prompting tips When asking an agent to integrate Bora Pesa, a prompt like this works well once the MCP server is connected: ```text Add mobile money checkout to this app using @borapesa/pesa with the ClickPesa provider. Use the borapesa MCP tools to check provider config fields and copy the webhook mounting pattern for my framework. ``` Useful facts agents should know (all enforced by SDK validation): - Amounts are whole TZS integers: `15000` means TZS 15,000. Floats are rejected. - Phone numbers use MSISDN format `255XXXXXXXXX`. Local `07XX` numbers are rejected. - Only `provider` is required in `createPesa()`. The event store defaults to in-memory. - `pesa.mountWebhook` is a standard fetch handler serving `POST {basePath}/webhook`, `basePath` defaults to `/pesa`. - All provider calls are server-side. Never expose credentials to the browser. --- # Class: AzamPayPaymentProvider Defined in: [providers/azampay/src/azampay.ts:148](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L148) ## Extends - `BasePaymentProvider` ## Constructors ### Constructor ```ts new AzamPayPaymentProvider(config): AzamPayPaymentProvider; ``` Defined in: [providers/azampay/src/azampay.ts:166](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L166) #### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`AzamPayConfig`](../interfaces/AzamPayConfig) | #### Returns `AzamPayPaymentProvider` #### Overrides ```ts BasePaymentProvider.constructor ``` ## Properties | Property | Modifier | Type | Default value | Description | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `name` | `readonly` | `ProviderName` | `'azampay'` | Unique provider identifier. | `BasePaymentProvider.name` | [providers/azampay/src/azampay.ts:149](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L149) | ## Methods ### cancelOrder()? ```ts optional cancelOrder(_orderId): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:100 Cancel a pending or in-progress order. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | #### Returns `Promise`\<`CancelOrderResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support cancellation. #### Inherited from ```ts BasePaymentProvider.cancelOrder ``` *** ### createBankCheckout() ```ts createBankCheckout(params): Promise<{ success: boolean; transactionId: string; }>; ``` Defined in: [providers/azampay/src/azampay.ts:680](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L680) Bank checkout — accepts OTP from the customer (obtained via USSD). This is a two-step flow: 1. Customer dials `*150*03#` (CRDB) or `*150*66#` (NMB) to get OTP 2. Customer provides OTP to your app 3. Your app calls this method with the OTP #### Parameters | Parameter | Type | | ------ | ------ | | `params` | \{ `amount`: `string`; `merchantAccountNumber`: `string`; `merchantMobileNumber`: `string`; `merchantName?`: `string`; `otp`: `string`; `provider`: `"CRDB"` \| `"NMB"`; `referenceId`: `string`; \} | | `params.amount` | `string` | | `params.merchantAccountNumber` | `string` | | `params.merchantMobileNumber` | `string` | | `params.merchantName?` | `string` | | `params.otp` | `string` | | `params.provider` | `"CRDB"` \| `"NMB"` | | `params.referenceId` | `string` | #### Returns `Promise`\<\{ `success`: `boolean`; `transactionId`: `string`; \}\> *** ### createOrder() ```ts createOrder(payload): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:373](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L373) Initiate a checkout / USSD push / redirect. The SDK calls `validateCreateOrderPayload()` before this, so you can assume `amount > 0`, `reference` is non-empty, and `customer.phone` is in MSISDN format. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `CreateOrderPayload` | #### Returns `Promise`\<`OrderResult`\> #### Overrides ```ts BasePaymentProvider.createOrder ``` *** ### createPostCheckout() ```ts createPostCheckout(params): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:706](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L706) Generate a hosted checkout page URL. Returns the URL to redirect to. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | \{ `amount`: `string`; `currency`: `string`; `externalId`: `string`; `items?`: \{ `name`: `string`; \}[]; `language?`: `string`; `redirectFailURL`: `string`; `redirectSuccessURL`: `string`; `vendorId`: `string`; `vendorName`: `string`; \} | | `params.amount` | `string` | | `params.currency` | `string` | | `params.externalId` | `string` | | `params.items?` | \{ `name`: `string`; \}[] | | `params.language?` | `string` | | `params.redirectFailURL` | `string` | | `params.redirectSuccessURL` | `string` | | `params.vendorId` | `string` | | `params.vendorName` | `string` | #### Returns `Promise`\<`string`\> *** ### disburse() ```ts disburse(payload): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:508](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L508) Disburse (B2C payout). Uses the **disbursement** base URL per the OpenAPI spec. Response uses `pgReferenceId` (spec field), not `data`. `transferDetails.dateInEpoch` per spec (epoch seconds, not ISO string). `bankName` fields use lowercase enum values (`tigo`, `airtel`, `azampesa`). #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`DisburseResult`\> #### Overrides ```ts BasePaymentProvider.disburse ``` *** ### getBalance()? ```ts optional getBalance(): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:125 Retrieve available balances across all active currencies. Useful for dashboards, pre-disbursement checks, and wallet health monitoring. Returns per-currency balance entries with raw provider data for advanced use. #### Returns `Promise`\<`BalanceResult`\> `{ balances: [...] }` with per-currency entries. #### Throws `PesaUnsupportedError` — if the provider does not expose balance data. #### Since 0.2.0 #### Inherited from ```ts BasePaymentProvider.getBalance ``` *** ### getNameLookup() ```ts getNameLookup(phoneOrAccount): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:629](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L629) Name lookup. Uses the **disbursement** base URL per the OpenAPI spec. Accepts `status` field from the spec; falls back to `success` for provider implementations that deviate from their own spec. #### Parameters | Parameter | Type | | ------ | ------ | | `phoneOrAccount` | `string` | #### Returns `Promise`\<`NameLookupResult`\> #### Overrides ```ts BasePaymentProvider.getNameLookup ``` *** ### getPaymentPartners() ```ts getPaymentPartners(): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:753](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L753) List available payment partners for the configured merchant. The AzamPay spec returns a **bare JSON array** of partner objects, not a `{ partners: [...] }` wrapper. #### Returns `Promise`\<`PartnerResponse`[]\> *** ### getPaymentStatus() ```ts getPaymentStatus(orderId, providerName?): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:465](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L465) Query payment status. Uses the **disbursement** base URL per the OpenAPI spec. #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `orderId` | `string` | The AzamPay transaction ID returned by [createOrder](#createorder). | | `providerName?` | `string` | The MNO name for the query (e.g. `'airtel'`, `'tigo'`, `'azampesa'`). When called through the SDK, this is resolved automatically from the order-to-provider mapping stored by [createOrder](#createorder). Callers who bypass `createOrder` must pass it explicitly. | #### Returns `Promise`\<`PaymentStatus`\> #### Overrides ```ts BasePaymentProvider.getPaymentStatus ``` *** ### handleWebhook() ```ts handleWebhook(rawBody, _headers): Promise; ``` Defined in: [providers/azampay/src/azampay.ts:566](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L566) Parse and verify an incoming AzamPay callback (webhook). Matches the `CallbackRequest` schema from the AzamPay OpenAPI spec: `transactionstatus` (string), `transid`, `utilityref`, `operator`, `externalreference`, `msisdn`, `mnoreference`, `amount` (string), and `signature` (RSA base64). **Signature verification:** AzamPay signs callbacks with an RSA digital signature over `{utilityref}{externalreference}{transactionstatus}{operator}`. The public key is fetched from `GET /azampay/v1/public-key?format=Pem` (cached 24 hours). If the signature is absent (`null`), verification is skipped — this is accepted in the spec but should be logged for production. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `_headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)\> #### Overrides ```ts BasePaymentProvider.handleWebhook ``` *** ### listOrders()? ```ts optional listOrders(_params): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:153 List payment orders for a date range. #### Parameters | Parameter | Type | | ------ | ------ | | `_params` | `ListOrdersParams` | #### Returns `Promise`\<`ListOrdersResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support listing orders. #### Inherited from ```ts BasePaymentProvider.listOrders ``` *** ### previewDisburse()? ```ts optional previewDisburse(_payload): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:139 Preview / dry-run a disbursement before committing. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | `DisbursePayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Inherited from ```ts BasePaymentProvider.previewDisburse ``` *** ### previewOrder()? ```ts optional previewOrder(_payload): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:133 Preview / dry-run a payment before committing. Returns expected fees and validity without charging the customer. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | `CreateOrderPayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Inherited from ```ts BasePaymentProvider.previewOrder ``` *** ### refund()? ```ts optional refund(_orderId, _amount?): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:94 Refund a completed payment. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | | `_amount?` | `number` | #### Returns `Promise`\<`RefundResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support refunds. #### Inherited from ```ts BasePaymentProvider.refund ``` *** ### validateCredentials() ```ts validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [providers/azampay/src/azampay.ts:658](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L658) Validate that a provider config works (health check). Useful for startup checks or `/health` endpoints. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> `{ valid: true }` if credentials are correct. #### Throws `PesaUnsupportedError` — if the provider does not support validation. #### Overrides ```ts BasePaymentProvider.validateCredentials ``` --- # @borapesa/azampay ## Classes | Class | Description | | ------ | ------ | | [AzamPayPaymentProvider](classes/AzamPayPaymentProvider) | - | ## Interfaces | Interface | Description | | ------ | ------ | | [AzamPayConfig](interfaces/AzamPayConfig) | - | --- # Interface: AzamPayConfig Defined in: [providers/azampay/src/azampay.ts:32](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L32) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `apiKey` | `string` | API key from AzamPay dashboard. | [providers/azampay/src/azampay.ts:40](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L40) | | `appName` | `string` | App name from AzamPay dashboard. | [providers/azampay/src/azampay.ts:34](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L34) | | `authBaseUrl?` | `string` | Override auth base URL. | [providers/azampay/src/azampay.ts:48](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L48) | | `checkoutBaseUrl?` | `string` | Override checkout base URL. | [providers/azampay/src/azampay.ts:50](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L50) | | `clientId` | `string` | Client ID from AzamPay dashboard. | [providers/azampay/src/azampay.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L36) | | `clientSecret` | `string` | Client secret from AzamPay dashboard. | [providers/azampay/src/azampay.ts:38](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L38) | | `disbursementBaseUrl?` | `string` | Override disbursement base URL. The AzamPay API uses a **separate host** for disbursement endpoints (`disburse`, `getNameLookup`, `getPaymentStatus`). Defaults to `https://api-disbursement-sandbox.azampay.co.tz` (sandbox) or `https://api-disbursement.azampay.co.tz` (production). | [providers/azampay/src/azampay.ts:59](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L59) | | `sandbox?` | `boolean` | Target sandbox (default: true). | [providers/azampay/src/azampay.ts:46](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L46) | | `senderBank?` | `string` | Sender/merchant bank name for disbursement (default: "AzamPay"). | [providers/azampay/src/azampay.ts:44](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L44) | | `senderName` | `string` | Sender/merchant display name for disbursement transfers. | [providers/azampay/src/azampay.ts:42](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/azampay/src/azampay.ts#L42) | --- # Class: ClickPesaProvider Defined in: [providers/clickpesa/src/clickpesa.ts:162](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L162) ## Extends - `BasePaymentProvider` ## Constructors ### Constructor ```ts new ClickPesaProvider(config): ClickPesaProvider; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:178](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L178) #### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`ClickPesaConfig`](../interfaces/ClickPesaConfig) | #### Returns `ClickPesaProvider` #### Overrides ```ts BasePaymentProvider.constructor ``` ## Properties | Property | Modifier | Type | Default value | Description | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `name` | `readonly` | `ProviderName` | `'clickpesa'` | Unique provider identifier. | `BasePaymentProvider.name` | [providers/clickpesa/src/clickpesa.ts:163](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L163) | ## Methods ### bulkCreateCustomerNumbers() ```ts bulkCreateCustomerNumbers(controlNumbers): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:854](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L854) Bulk-create up to 50 customer control numbers in a single request. #### Parameters | Parameter | Type | | ------ | ------ | | `controlNumbers` | `Record`\<`string`, `unknown`\>[] | #### Returns `Promise`\<`BillPayBulkResult`\> *** ### bulkCreateOrderNumbers() ```ts bulkCreateOrderNumbers(controlNumbers): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:841](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L841) Bulk-create up to 50 order control numbers in a single request. #### Parameters | Parameter | Type | | ------ | ------ | | `controlNumbers` | `Record`\<`string`, `unknown`\>[] | #### Returns `Promise`\<`BillPayBulkResult`\> *** ### cancelOrder()? ```ts optional cancelOrder(_orderId): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:100 Cancel a pending or in-progress order. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | #### Returns `Promise`\<`CancelOrderResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support cancellation. #### Inherited from ```ts BasePaymentProvider.cancelOrder ``` *** ### createChecksum() ```ts createChecksum(payload): string; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:923](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L923) **`Internal`** Create a ClickPesa-compatible HMAC-SHA256 checksum for a request body. Algorithm (per ClickPesa docs): 1. Canonicalize — recursively sort all object keys alphabetically. 2. Serialize to compact JSON (no whitespace). 3. Return hex digest of HMAC-SHA256(key, json_string). Exposed for testing via the provider instance. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `Record`\<`string`, `unknown`\> | #### Returns `string` *** ### createCustomerControlNumber() ```ts createCustomerControlNumber(params): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:815](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L815) Generate a persistent control number tied to a specific customer. At least one of `phone` or `email` must be supplied. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | \{ `amount?`: `number`; `billReference?`: `string`; `customerName`: `string`; `description?`: `string`; `email?`: `string`; `paymentMode?`: `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"`; `phone?`: `string`; \} | | `params.amount?` | `number` | | `params.billReference?` | `string` | | `params.customerName` | `string` | | `params.description?` | `string` | | `params.email?` | `string` | | `params.paymentMode?` | `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"` | | `params.phone?` | `string` | #### Returns `Promise`\<`BillPayControlNumber`\> *** ### createOrder() ```ts createOrder(payload): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:306](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L306) Initiate a checkout / USSD push / redirect. The SDK calls `validateCreateOrderPayload()` before this, so you can assume `amount > 0`, `reference` is non-empty, and `customer.phone` is in MSISDN format. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `CreateOrderPayload` | #### Returns `Promise`\<`OrderResult`\> #### Overrides ```ts BasePaymentProvider.createOrder ``` *** ### createOrderControlNumber() ```ts createOrderControlNumber(params?): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:794](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L794) Generate a one-time order control number. Customers pay this number via mobile money, SIM banking, or CRDB Wakala. All fields are optional — the API auto-generates a reference if omitted. #### Parameters | Parameter | Type | | ------ | ------ | | `params?` | \{ `amount?`: `number`; `billReference?`: `string`; `description?`: `string`; `paymentMode?`: `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"`; \} | | `params.amount?` | `number` | | `params.billReference?` | `string` | | `params.description?` | `string` | | `params.paymentMode?` | `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"` | #### Returns `Promise`\<`BillPayControlNumber`\> *** ### disburse() ```ts disburse(payload): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:473](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L473) B2C / wallet-out disbursement. The SDK calls `validateDisbursePayload()` before this. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`DisburseResult`\> #### Overrides ```ts BasePaymentProvider.disburse ``` *** ### generatePayoutLink() ```ts generatePayoutLink(amount, orderId): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:651](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L651) Generate a hosted payout link. The recipient uses the link to enter their own bank or mobile-money details — you don't need to collect them yourself. Returns a URL you redirect the recipient to. #### Parameters | Parameter | Type | | ------ | ------ | | `amount` | `number` | | `orderId` | `string` | #### Returns `Promise`\<`string`\> *** ### getAccountStatement() ```ts getAccountStatement( currency?, startDate?, endDate?): Promise<{ accountDetails: Record; transactions: Record[]; }>; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:698](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L698) Fetch a transaction statement for a given currency. #### Parameters | Parameter | Type | Default value | Description | | ------ | ------ | ------ | ------ | | `currency` | `string` | `'TZS'` | — `"TZS"` (default) or `"USD"`. | | `startDate?` | `Date` | `undefined` | — Optional filter: start date. | | `endDate?` | `Date` | `undefined` | — Optional filter: end date. | #### Returns `Promise`\<\{ `accountDetails`: `Record`\<`string`, `unknown`\>; `transactions`: `Record`\<`string`, `unknown`\>[]; \}\> *** ### getBalance() ```ts getBalance(): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:536](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L536) Retrieve available balances across all active currencies. Useful for dashboards, pre-disbursement checks, and wallet health monitoring. Returns per-currency balance entries with raw provider data for advanced use. #### Returns `Promise`\<`BalanceResult`\> `{ balances: [...] }` with per-currency entries. #### Throws `PesaUnsupportedError` — if the provider does not expose balance data. #### Since 0.2.0 #### Overrides ```ts BasePaymentProvider.getBalance ``` *** ### getBanks() ```ts getBanks(): Promise<{ bic: string; name: string; value?: string; }[]>; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:684](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L684) #### Returns `Promise`\<\{ `bic`: `string`; `name`: `string`; `value?`: `string`; \}[]\> *** ### getBillPayDetails() ```ts getBillPayDetails(billPayNumber): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:867](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L867) Query details of a specific control number. #### Parameters | Parameter | Type | | ------ | ------ | | `billPayNumber` | `string` | #### Returns `Promise`\<`BillPayControlNumber`\> *** ### getExchangeRates() ```ts getExchangeRates(source?, target?): Promise<{ date: string; rate: number; source: string; target: string; }[]>; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:671](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L671) Fetch the latest exchange rates. #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `source?` | `string` | — ISO 4217 source currency (e.g. `"USD"`). All sources when omitted. | | `target?` | `string` | — ISO 4217 target currency (e.g. `"TZS"`). All targets when omitted. | #### Returns `Promise`\<\{ `date`: `string`; `rate`: `number`; `source`: `string`; `target`: `string`; \}[]\> *** ### getNameLookup() ```ts getNameLookup(phoneOrAccount): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:716](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L716) Resolve the account holder name for a phone or account number. Useful for verifying recipient identity before disbursing. #### Parameters | Parameter | Type | | ------ | ------ | | `phoneOrAccount` | `string` | #### Returns `Promise`\<`NameLookupResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support name lookup. #### Overrides ```ts BasePaymentProvider.getNameLookup ``` *** ### getPaymentStatus() ```ts getPaymentStatus(orderId): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:399](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L399) Poll or fetch the current payment status for an order. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<`PaymentStatus`\> #### Overrides ```ts BasePaymentProvider.getPaymentStatus ``` *** ### handleWebhook() ```ts handleWebhook(rawBody, headers): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:418](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L418) Parse + verify an incoming webhook. The provider must: 1. Verify its own cryptographic signature (HMAC, checksum, etc.) 2. Parse the raw body into structured data 3. Return a normalized [PaymentEvent](/docs/api/pesa/interfaces/PaymentEvent) The SDK handles UUID assignment, event persistence, plugin hooks, and user-registered handler emission after this method returns. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)\> #### Overrides ```ts BasePaymentProvider.handleWebhook ``` *** ### listOrders() ```ts listOrders(params): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:739](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L739) List payment orders for a date range. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | `ListOrdersParams` | #### Returns `Promise`\<`ListOrdersResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support listing orders. #### Overrides ```ts BasePaymentProvider.listOrders ``` *** ### previewDisburse() ```ts previewDisburse(payload): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:598](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L598) Preview / dry-run a disbursement before committing. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Overrides ```ts BasePaymentProvider.previewDisburse ``` *** ### previewOrder() ```ts previewOrder(payload): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:551](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L551) Preview / dry-run a payment before committing. Returns expected fees and validity without charging the customer. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `CreateOrderPayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Overrides ```ts BasePaymentProvider.previewOrder ``` *** ### refund()? ```ts optional refund(_orderId, _amount?): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:94 Refund a completed payment. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | | `_amount?` | `number` | #### Returns `Promise`\<`RefundResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support refunds. #### Inherited from ```ts BasePaymentProvider.refund ``` *** ### updateBillPayReference() ```ts updateBillPayReference(billPayNumber, params): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:877](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L877) Partially update a BillPay reference. At least one field besides `billPayNumber` must be provided. #### Parameters | Parameter | Type | | ------ | ------ | | `billPayNumber` | `string` | | `params` | \{ `amount?`: `number`; `description?`: `string`; `paymentMode?`: `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"`; `status?`: `"ACTIVE"` \| `"INACTIVE"`; \} | | `params.amount?` | `number` | | `params.description?` | `string` | | `params.paymentMode?` | `"ALLOW_PARTIAL_AND_OVER_PAYMENT"` \| `"EXACT"` | | `params.status?` | `"ACTIVE"` \| `"INACTIVE"` | #### Returns `Promise`\<`BillPayControlNumber`\> *** ### updateBillPayStatus() ```ts updateBillPayStatus(billPayNumber, status): Promise; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:901](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L901) Activate or deactivate a control number (convenience wrapper). #### Parameters | Parameter | Type | | ------ | ------ | | `billPayNumber` | `string` | | `status` | `"ACTIVE"` \| `"INACTIVE"` | #### Returns `Promise`\<`BillPayControlNumber`\> *** ### validateCredentials() ```ts validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [providers/clickpesa/src/clickpesa.ts:527](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L527) Validate that a provider config works (health check). Useful for startup checks or `/health` endpoints. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> `{ valid: true }` if credentials are correct. #### Throws `PesaUnsupportedError` — if the provider does not support validation. #### Overrides ```ts BasePaymentProvider.validateCredentials ``` --- # @borapesa/clickpesa ## Classes | Class | Description | | ------ | ------ | | [ClickPesaProvider](classes/ClickPesaProvider) | - | ## Interfaces | Interface | Description | | ------ | ------ | | [ClickPesaConfig](interfaces/ClickPesaConfig) | - | --- # Interface: ClickPesaConfig Defined in: [providers/clickpesa/src/clickpesa.ts:31](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L31) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `apiKey` | `string` | API key from ClickPesa dashboard. | [providers/clickpesa/src/clickpesa.ts:35](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L35) | | `baseUrl?` | `string` | Explicit base URL override. Takes precedence over `sandbox`. You rarely need this — prefer `sandbox: true` for testing and `sandbox: false` for production. | [providers/clickpesa/src/clickpesa.ts:60](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L60) | | `checksumKey?` | `string` | Optional checksum key for HMAC-SHA256 signing. When set, every POST/PUT/PATCH request body is automatically signed with a `checksum` field. Also used for verifying incoming webhook signatures. Generate this in the ClickPesa dashboard. | [providers/clickpesa/src/clickpesa.ts:43](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L43) | | `clientId` | `string` | Client ID from ClickPesa dashboard. | [providers/clickpesa/src/clickpesa.ts:33](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L33) | | `redirectUrl?` | `string` | Default redirect URL for hosted checkout. The customer is sent here after completing payment. Overridable per-payment via CreateOrderPayload.redirectUrl. | [providers/clickpesa/src/clickpesa.ts:66](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L66) | | `sandbox?` | `boolean` | Target the sandbox environment. When `true`, defaults to `https://api-sandbox.clickpesa.com`. When `false` (default), uses `https://api.clickpesa.com`. Set `baseUrl` directly to override both — useful for local proxies or staging environments. | [providers/clickpesa/src/clickpesa.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/clickpesa/src/clickpesa.ts#L53) | --- # Function: isAvailable() ```ts function isAvailable(binary?): boolean; ``` Defined in: [packages/devtools/src/tunnel.ts:301](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L301) ## Parameters | Parameter | Type | Default value | | ------ | ------ | ------ | | `binary` | `string` | `'cloudflared'` | ## Returns `boolean` --- # Function: startTunnel() ```ts function startTunnel(port, binary?): Promise; ``` Defined in: [packages/devtools/src/tunnel.ts:111](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L111) ## Parameters | Parameter | Type | Default value | | ------ | ------ | ------ | | `port` | `number` | `undefined` | | `binary` | `string` | `'cloudflared'` | ## Returns `Promise`\<[`Tunnel`](../interfaces/Tunnel)\> --- # Function: tunnelPlugin() ```ts function tunnelPlugin(opts?): PesaPlugin; ``` Defined in: [packages/devtools/src/tunnel.ts:247](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L247) A borapesa plugin that starts a Cloudflare Quick Tunnel for local webhook development. Requires `cloudflared` on the system PATH (free, no account needed). The tunnel persists across Bun/Node --watch reloads — the same URL is reused between restarts so you don't need to reconfigure your provider dashboard on every file change. ```ts import { createPesa } from '@borapesa/pesa'; import { tunnelPlugin } from '@borapesa/devtools'; const pesa = createPesa({ provider: new SelcomPaymentProvider({...}), plugins: [tunnelPlugin()], }); // First launch: // 🛜 @borapesa/tunnel // Tunnel ready: https://xxx.trycloudflare.com // Webhook URL: https://xxx.trycloudflare.com/pesa/webhook (or custom webhookPath) // // Subsequent Bun --watch reloads: (silent — reuses same URL) ``` ## Parameters | Parameter | Type | | ------ | ------ | | `opts` | [`TunnelPluginOptions`](../interfaces/TunnelPluginOptions) | ## Returns `PesaPlugin` --- # @borapesa/devtools ## Interfaces | Interface | Description | | ------ | ------ | | [Tunnel](interfaces/Tunnel) | - | | [TunnelPluginOptions](interfaces/TunnelPluginOptions) | - | ## Functions | Function | Description | | ------ | ------ | | [isAvailable](functions/isAvailable) | - | | [startTunnel](functions/startTunnel) | - | | [tunnelPlugin](functions/tunnelPlugin) | A borapesa plugin that starts a Cloudflare Quick Tunnel for local webhook development. Requires `cloudflared` on the system PATH (free, no account needed). | --- # Interface: Tunnel Defined in: [packages/devtools/src/tunnel.ts:105](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L105) ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `close` | () => `void` | [packages/devtools/src/tunnel.ts:108](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L108) | | `pid` | `number` | [packages/devtools/src/tunnel.ts:107](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L107) | | `url` | `string` | [packages/devtools/src/tunnel.ts:106](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L106) | --- # Interface: TunnelPluginOptions Defined in: [packages/devtools/src/tunnel.ts:194](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L194) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `binary?` | `string` | Override the cloudflared binary path or name. Useful for testing with a mock binary that mimics cloudflared's I/O. **Default** `'cloudflared'` | [packages/devtools/src/tunnel.ts:212](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L212) | | `log?` | `boolean` | Whether to print the tunnel URL to the console. **Default** `true` | [packages/devtools/src/tunnel.ts:205](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L205) | | `port?` | `number` | The local port to expose via the tunnel. **Default** `3000` | [packages/devtools/src/tunnel.ts:199](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L199) | | `webhookPath?` | `string` | The webhook endpoint path on your server. Printed in the console as the webhook URL to use for provider callbacks. **Default** `'/pesa/webhook'` | [packages/devtools/src/tunnel.ts:219](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/devtools/src/tunnel.ts#L219) | --- # API Reference Bora Pesa API reference — auto-generated from JSDoc. ## Packages | Package | Description | | --- | --- | | [@borapesa/pesa](pesa) | Core — types, factory, event store, plugins | | [@borapesa/azampay](azampay) | AzamPay provider adapter | | [@borapesa/clickpesa](clickpesa) | ClickPesa provider adapter | | [@borapesa/selcom](selcom) | Selcom provider adapter | | [@borapesa/snippe](snippe) | Snippe provider adapter | | [@borapesa/sqlite](sqlite) | SQLite event store adapter | | [@borapesa/devtools](devtools) | Developer tools — cloudflared tunnel, webhook dev utilities | | [@borapesa/mcp](mcp) | MCP server — searchable docs, provider registry, and examples for AI agents | --- # Function: buildIndex() ```ts function buildIndex(docs): SearchIndex; ``` Defined in: [packages/mcp/src/search.ts:47](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L47) ## Parameters | Parameter | Type | | ------ | ------ | | `docs` | [`Doc`](../interfaces/Doc)[] | ## Returns [`SearchIndex`](../interfaces/SearchIndex) --- # Function: createBorapesaMcpServer() ```ts function createBorapesaMcpServer(options?): McpServer; ``` Defined in: [packages/mcp/src/server.ts:43](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/server.ts#L43) Build the Bora Pesa MCP server with all tools and resources registered. ## Parameters | Parameter | Type | | ------ | ------ | | `options` | [`CreateServerOptions`](../interfaces/CreateServerOptions) | ## Returns `McpServer` --- # Function: exampleTopics() ```ts function exampleTopics(): string[]; ``` Defined in: [packages/mcp/src/examples.ts:364](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L364) ## Returns `string`[] --- # Function: getExample() ```ts function getExample(topic): Example | undefined; ``` Defined in: [packages/mcp/src/examples.ts:360](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L360) ## Parameters | Parameter | Type | | ------ | ------ | | `topic` | `string` | ## Returns [`Example`](../interfaces/Example) \| `undefined` --- # Function: getProvider() ```ts function getProvider(id): ProviderInfo | undefined; ``` Defined in: [packages/mcp/src/providers.ts:319](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L319) ## Parameters | Parameter | Type | | ------ | ------ | | `id` | `string` | ## Returns [`ProviderInfo`](../interfaces/ProviderInfo) \| `undefined` --- # Function: loadDocStore() ```ts function loadDocStore(contentDir?): DocStore; ``` Defined in: [packages/mcp/src/content.ts:58](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L58) Load the docs manifest and expose lazy page access. ## Parameters | Parameter | Type | | ------ | ------ | | `contentDir?` | `string` | ## Returns [`DocStore`](../interfaces/DocStore) --- # Function: search() ```ts function search( index, query, limit?): SearchResult[]; ``` Defined in: [packages/mcp/src/search.ts:95](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L95) Rank docs against a keyword query. Weights: title/description hits dominate, then headings and the page path, then body term frequency. Guides outrank generated API reference pages at equal score so agents land on conceptual pages first. ## Parameters | Parameter | Type | Default value | | ------ | ------ | ------ | | `index` | [`SearchIndex`](../interfaces/SearchIndex) | `undefined` | | `query` | `string` | `undefined` | | `limit` | `number` | `8` | ## Returns [`SearchResult`](../interfaces/SearchResult)[] --- # Function: tokenize() ```ts function tokenize(text): string[]; ``` Defined in: [packages/mcp/src/search.ts:32](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L32) Lowercase alphanumeric tokens, minimum two characters. Trailing-s stemming (webhooks -> webhook) is applied identically to the index and the query, so plural and singular forms always match. Stems are prefixes of the original word, which keeps snippet lookup working. ## Parameters | Parameter | Type | | ------ | ------ | | `text` | `string` | ## Returns `string`[] --- # @borapesa/mcp ## Interfaces | Interface | Description | | ------ | ------ | | [ConfigField](interfaces/ConfigField) | Structured registry of every Bora Pesa payment provider. | | [CreateServerOptions](interfaces/CreateServerOptions) | - | | [Doc](interfaces/Doc) | A fully loaded docs page. | | [DocEntry](interfaces/DocEntry) | One entry in the bundled docs manifest. | | [DocStore](interfaces/DocStore) | - | | [Example](interfaces/Example) | Curated, runnable code examples for common Bora Pesa tasks. | | [ProviderInfo](interfaces/ProviderInfo) | - | | [SearchIndex](interfaces/SearchIndex) | - | | [SearchResult](interfaces/SearchResult) | - | ## Variables | Variable | Description | | ------ | ------ | | [EXAMPLES](variables/EXAMPLES) | - | | [PROVIDERS](variables/PROVIDERS) | - | ## Functions | Function | Description | | ------ | ------ | | [buildIndex](functions/buildIndex) | - | | [createBorapesaMcpServer](functions/createBorapesaMcpServer) | Build the Bora Pesa MCP server with all tools and resources registered. | | [exampleTopics](functions/exampleTopics) | - | | [getExample](functions/getExample) | - | | [getProvider](functions/getProvider) | - | | [loadDocStore](functions/loadDocStore) | Load the docs manifest and expose lazy page access. | | [search](functions/search) | Rank docs against a keyword query. | | [tokenize](functions/tokenize) | Lowercase alphanumeric tokens, minimum two characters. | --- # Interface: ConfigField Defined in: [packages/mcp/src/providers.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L9) Structured registry of every Bora Pesa payment provider. Hand-curated from the provider source code so agents can answer "which provider should I use and how do I configure it" without reading the full docs. Keep in sync when provider configs change. ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `description` | `string` | [packages/mcp/src/providers.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L12) | | `name` | `string` | [packages/mcp/src/providers.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L10) | | `required` | `boolean` | [packages/mcp/src/providers.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L11) | --- # Interface: CreateServerOptions Defined in: [packages/mcp/src/server.ts:37](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/server.ts#L37) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `contentDir?` | `string` | Override the bundled docs directory (mainly for tests). | [packages/mcp/src/server.ts:39](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/server.ts#L39) | --- # Interface: Doc Defined in: [packages/mcp/src/content.ts:17](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L17) A fully loaded docs page. ## Extends - [`DocEntry`](DocEntry) ## Properties | Property | Type | Description | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `body` | `string` | - | - | [packages/mcp/src/content.ts:18](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L18) | | `description` | `string` | - | [`DocEntry`](DocEntry).[`description`](DocEntry.md#description) | [packages/mcp/src/content.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L10) | | `path` | `string` | Slug relative to the docs root, e.g. `getting-started` or `api/pesa/index`. | [`DocEntry`](DocEntry).[`path`](DocEntry.md#path) | [packages/mcp/src/content.ts:8](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L8) | | `section` | `"guides"` \| `"api"` | - | [`DocEntry`](DocEntry).[`section`](DocEntry.md#section) | [packages/mcp/src/content.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L11) | | `title` | `string` | - | [`DocEntry`](DocEntry).[`title`](DocEntry.md#title) | [packages/mcp/src/content.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L9) | | `url` | `string` | Canonical page URL on borapesa.dev. | [`DocEntry`](DocEntry).[`url`](DocEntry.md#url) | [packages/mcp/src/content.ts:13](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L13) | --- # Interface: DocEntry Defined in: [packages/mcp/src/content.ts:6](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L6) One entry in the bundled docs manifest. ## Extended by - [`Doc`](Doc) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `description` | `string` | - | [packages/mcp/src/content.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L10) | | `path` | `string` | Slug relative to the docs root, e.g. `getting-started` or `api/pesa/index`. | [packages/mcp/src/content.ts:8](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L8) | | `section` | `"guides"` \| `"api"` | - | [packages/mcp/src/content.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L11) | | `title` | `string` | - | [packages/mcp/src/content.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L9) | | `url` | `string` | Canonical page URL on borapesa.dev. | [packages/mcp/src/content.ts:13](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L13) | --- # Interface: DocStore Defined in: [packages/mcp/src/content.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L21) ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `entries` | [`DocEntry`](DocEntry)[] | [packages/mcp/src/content.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L22) | ## Methods ### allDocs() ```ts allDocs(): Doc[]; ``` Defined in: [packages/mcp/src/content.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L26) Load every page (cached after first call). #### Returns [`Doc`](Doc)[] *** ### getDoc() ```ts getDoc(path): Doc; ``` Defined in: [packages/mcp/src/content.ts:24](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/content.ts#L24) Load a single page by manifest path. Throws on unknown paths. #### Parameters | Parameter | Type | | ------ | ------ | | `path` | `string` | #### Returns [`Doc`](Doc) --- # Interface: Example Defined in: [packages/mcp/src/examples.ts:8](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L8) Curated, runnable code examples for common Bora Pesa tasks. Every snippet is verified against the current public API. When the SDK surface changes, update these alongside the docs. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `code` | `string` | - | [packages/mcp/src/examples.ts:14](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L14) | | `description` | `string` | - | [packages/mcp/src/examples.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L11) | | `docsPath` | `string` | Docs page with the full explanation, e.g. `getting-started`. | [packages/mcp/src/examples.ts:13](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L13) | | `title` | `string` | - | [packages/mcp/src/examples.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L10) | | `topic` | `string` | - | [packages/mcp/src/examples.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L9) | --- # Interface: ProviderInfo Defined in: [packages/mcp/src/providers.ts:15](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L15) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `auth` | `string` | - | [packages/mcp/src/providers.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L21) | | `className` | `string` | - | [packages/mcp/src/providers.ts:18](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L18) | | `configFields` | [`ConfigField`](ConfigField)[] | - | [packages/mcp/src/providers.ts:24](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L24) | | `coreCapabilities` | `string`[] | The 4 methods every provider implements. | [packages/mcp/src/providers.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L26) | | `id` | `string` | - | [packages/mcp/src/providers.ts:16](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L16) | | `importExample` | `string` | - | [packages/mcp/src/providers.ts:31](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L31) | | `optionalCapabilities` | `string`[] | Optional PesaInstance methods this provider supports. | [packages/mcp/src/providers.ts:28](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L28) | | `package` | `string` | - | [packages/mcp/src/providers.ts:17](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L17) | | `providerSpecific` | `string`[] | Provider-specific methods beyond the shared interface. | [packages/mcp/src/providers.ts:30](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L30) | | `sandbox` | `string` | - | [packages/mcp/src/providers.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L22) | | `status` | `"available"` \| `"planned"` \| `"testing-only"` | - | [packages/mcp/src/providers.ts:19](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L19) | | `summary` | `string` | - | [packages/mcp/src/providers.ts:20](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L20) | | `webhookVerification` | `string` | - | [packages/mcp/src/providers.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L23) | --- # Interface: SearchIndex Defined in: [packages/mcp/src/search.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L21) ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `docs` | `IndexedDoc`[] | [packages/mcp/src/search.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L22) | --- # Interface: SearchResult Defined in: [packages/mcp/src/search.ts:3](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L3) ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `description` | `string` | [packages/mcp/src/search.ts:6](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L6) | | `path` | `string` | [packages/mcp/src/search.ts:4](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L4) | | `score` | `number` | [packages/mcp/src/search.ts:8](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L8) | | `snippet` | `string` | [packages/mcp/src/search.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L9) | | `title` | `string` | [packages/mcp/src/search.ts:5](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L5) | | `url` | `string` | [packages/mcp/src/search.ts:7](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/search.ts#L7) | --- # Variable: EXAMPLES ```ts const EXAMPLES: Example[]; ``` Defined in: [packages/mcp/src/examples.ts:17](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/examples.ts#L17) --- # Variable: PROVIDERS ```ts const PROVIDERS: ProviderInfo[]; ``` Defined in: [packages/mcp/src/providers.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/mcp/src/providers.ts#L36) --- # Abstract Class: BasePaymentProvider Defined in: [packages/pesa/src/providers/base.ts:75](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L75) Abstract base class every provider adapter must implement. ## Since 0.1.0 The SDK calls only these methods — no provider-specific logic ever leaks into application code. ## Required methods (must implement) - [createOrder](#createorder) — initiate a checkout / USSD push / redirect - [getPaymentStatus](#getpaymentstatus) — poll or fetch current payment status - [handleWebhook](#handlewebhook) — parse + verify an incoming webhook - [disburse](#disburse) — B2C / wallet-out disbursement ## Optional methods (override to enable) Default implementations throw [PesaUnsupportedError](PesaUnsupportedError). Applications can feature-detect capability: ```ts if (pesa.getBalance) { const { balances } = await pesa.getBalance(); console.log(`TZS balance: ${balances.find(b => b.currency === 'TZS')?.amount}`); } ``` ## Writing a provider adapter ```ts import { BasePaymentProvider } from '@borapesa/pesa'; import type { ProviderName, CreateOrderPayload, OrderResult } from '@borapesa/pesa'; export class MyProvider extends BasePaymentProvider { readonly name: ProviderName = 'selcom'; async createOrder(payload: CreateOrderPayload): Promise { // Call your provider's API const res = await fetch('https://api.provider.com/order', { method: 'POST', body: JSON.stringify(payload), }); const data = await res.json(); return { orderId: data.transactionId, reference: payload.reference, status: 'PENDING', }; } async getPaymentStatus(orderId: string): Promise { ... } async handleWebhook(rawBody, headers): Promise { ... } async disburse(payload): Promise { ... } } ``` ## Constructors ### Constructor ```ts new BasePaymentProvider(): BasePaymentProvider; ``` #### Returns `BasePaymentProvider` ## Properties | Property | Modifier | Type | Description | Defined in | | ------ | ------ | ------ | ------ | ------ | | `name` | `abstract` | [`ProviderName`](../type-aliases/ProviderName) | Unique provider identifier. | [packages/pesa/src/providers/base.ts:77](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L77) | ## Methods ### cancelOrder()? ```ts optional cancelOrder(_orderId): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:132](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L132) Cancel a pending or in-progress order. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | #### Returns `Promise`\<[`CancelOrderResult`](../interfaces/CancelOrderResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support cancellation. *** ### createOrder() ```ts abstract createOrder(payload): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:88](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L88) Initiate a checkout / USSD push / redirect. The SDK calls `validateCreateOrderPayload()` before this, so you can assume `amount > 0`, `reference` is non-empty, and `customer.phone` is in MSISDN format. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`CreateOrderPayload`](../interfaces/CreateOrderPayload) | #### Returns `Promise`\<[`OrderResult`](../interfaces/OrderResult)\> *** ### disburse() ```ts abstract disburse(payload): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:114](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L114) B2C / wallet-out disbursement. The SDK calls `validateDisbursePayload()` before this. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`DisbursePayload`](../interfaces/DisbursePayload) | #### Returns `Promise`\<[`DisburseResult`](../interfaces/DisburseResult)\> *** ### getBalance()? ```ts optional getBalance(): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:160](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L160) Retrieve available balances across all active currencies. Useful for dashboards, pre-disbursement checks, and wallet health monitoring. Returns per-currency balance entries with raw provider data for advanced use. #### Returns `Promise`\<[`BalanceResult`](../interfaces/BalanceResult)\> `{ balances: [...] }` with per-currency entries. #### Throws `PesaUnsupportedError` — if the provider does not expose balance data. #### Since 0.2.0 *** ### getNameLookup()? ```ts optional getNameLookup(_phoneOrAccount): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:191](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L191) Resolve the account holder name for a phone or account number. Useful for verifying recipient identity before disbursing. #### Parameters | Parameter | Type | | ------ | ------ | | `_phoneOrAccount` | `string` | #### Returns `Promise`\<[`NameLookupResult`](../interfaces/NameLookupResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support name lookup. *** ### getPaymentStatus() ```ts abstract getPaymentStatus(orderId): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:91](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L91) Poll or fetch the current payment status for an order. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`PaymentStatus`](../type-aliases/PaymentStatus)\> *** ### handleWebhook() ```ts abstract handleWebhook(rawBody, headers): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:104](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L104) Parse + verify an incoming webhook. The provider must: 1. Verify its own cryptographic signature (HMAC, checksum, etc.) 2. Parse the raw body into structured data 3. Return a normalized [PaymentEvent](../interfaces/PaymentEvent) The SDK handles UUID assignment, event persistence, plugin hooks, and user-registered handler emission after this method returns. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<[`PaymentEvent`](../interfaces/PaymentEvent)\> *** ### listOrders()? ```ts optional listOrders(_params): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:200](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L200) List payment orders for a date range. #### Parameters | Parameter | Type | | ------ | ------ | | `_params` | [`ListOrdersParams`](../interfaces/ListOrdersParams) | #### Returns `Promise`\<[`ListOrdersResult`](../interfaces/ListOrdersResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support listing orders. *** ### previewDisburse()? ```ts optional previewDisburse(_payload): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:180](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L180) Preview / dry-run a disbursement before committing. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | [`DisbursePayload`](../interfaces/DisbursePayload) | #### Returns `Promise`\<[`PreviewResult`](../interfaces/PreviewResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. *** ### previewOrder()? ```ts optional previewOrder(_payload): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:171](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L171) Preview / dry-run a payment before committing. Returns expected fees and validity without charging the customer. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | [`CreateOrderPayload`](../interfaces/CreateOrderPayload) | #### Returns `Promise`\<[`PreviewResult`](../interfaces/PreviewResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. *** ### refund()? ```ts optional refund(_orderId, _amount?): Promise; ``` Defined in: [packages/pesa/src/providers/base.ts:123](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L123) Refund a completed payment. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | | `_amount?` | `number` | #### Returns `Promise`\<[`RefundResult`](../interfaces/RefundResult)\> #### Throws `PesaUnsupportedError` — if the provider does not support refunds. *** ### validateCredentials()? ```ts optional validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [packages/pesa/src/providers/base.ts:144](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/providers/base.ts#L144) Validate that a provider config works (health check). Useful for startup checks or `/health` endpoints. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> `{ valid: true }` if credentials are correct. #### Throws `PesaUnsupportedError` — if the provider does not support validation. --- # Class: MemoryAdapter Defined in: [packages/pesa/src/db/memory.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/memory.ts#L11) In-memory event store — zero dependencies, perfect for dev and CI. This is the default adapter for borapesa. Events are stored in a Map and lost on process exit. For production, swap to a persistent adapter (e.g., `@borapesa/sqlite`, `@borapesa/postgres`). ## Implements - [`PesaDatabaseAdapter`](../interfaces/PesaDatabaseAdapter) ## Constructors ### Constructor ```ts new MemoryAdapter(): MemoryAdapter; ``` #### Returns `MemoryAdapter` ## Methods ### getEvent() ```ts getEvent(id): Promise; ``` Defined in: [packages/pesa/src/db/memory.ts:18](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/memory.ts#L18) Retrieve a single event by its UUID. #### Parameters | Parameter | Type | | ------ | ------ | | `id` | `string` | #### Returns `Promise`\<[`PaymentEvent`](../interfaces/PaymentEvent) \| `null`\> #### Implementation of [`PesaDatabaseAdapter`](../interfaces/PesaDatabaseAdapter).[`getEvent`](../interfaces/PesaDatabaseAdapter.md#getevent) *** ### getEventsByOrderId() ```ts getEventsByOrderId(orderId): Promise; ``` Defined in: [packages/pesa/src/db/memory.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/memory.ts#L26) Retrieve all events for a given provider order ID. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`PaymentEvent`](../interfaces/PaymentEvent)[]\> #### Implementation of [`PesaDatabaseAdapter`](../interfaces/PesaDatabaseAdapter).[`getEventsByOrderId`](../interfaces/PesaDatabaseAdapter.md#geteventsbyorderid) *** ### getEventsByReference() ```ts getEventsByReference(reference): Promise; ``` Defined in: [packages/pesa/src/db/memory.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/memory.ts#L22) Retrieve all events for a given merchant reference. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<[`PaymentEvent`](../interfaces/PaymentEvent)[]\> #### Implementation of [`PesaDatabaseAdapter`](../interfaces/PesaDatabaseAdapter).[`getEventsByReference`](../interfaces/PesaDatabaseAdapter.md#geteventsbyreference) *** ### saveEvent() ```ts saveEvent(event): Promise; ``` Defined in: [packages/pesa/src/db/memory.ts:14](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/memory.ts#L14) Persist a verified PaymentEvent. #### Parameters | Parameter | Type | | ------ | ------ | | `event` | [`PaymentEvent`](../interfaces/PaymentEvent) | #### Returns `Promise`\<`void`\> #### Implementation of [`PesaDatabaseAdapter`](../interfaces/PesaDatabaseAdapter).[`saveEvent`](../interfaces/PesaDatabaseAdapter.md#saveevent) --- # Class: PesaError Defined in: [packages/pesa/src/errors.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L9) Base error class for all Bora Pesa errors. ## Extends - `Error` ## Extended by - [`PesaNetworkError`](PesaNetworkError) - [`PesaProviderError`](PesaProviderError) - [`PesaUnsupportedError`](PesaUnsupportedError) - [`PesaValidationError`](PesaValidationError) - [`PesaWebhookError`](PesaWebhookError) ## Constructors ### Constructor ```ts new PesaError(message, code): PesaError; ``` Defined in: [packages/pesa/src/errors.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L10) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | | `code` | `string` | #### Returns `PesaError` #### Overrides ```ts Error.constructor ``` ## Properties | Property | Modifier | Type | Defined in | | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | --- # Class: PesaNetworkError Defined in: [packages/pesa/src/errors.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L36) Thrown when a provider API is unreachable or returns a network error. ## Extends - [`PesaError`](PesaError) ## Constructors ### Constructor ```ts new PesaNetworkError(message): PesaNetworkError; ``` Defined in: [packages/pesa/src/errors.ts:37](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L37) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | #### Returns `PesaNetworkError` #### Overrides [`PesaError`](PesaError).[`constructor`](PesaError.md#constructor) ## Properties | Property | Modifier | Type | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [`PesaError`](PesaError).[`code`](PesaError.md#code) | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | --- # Class: PesaProviderError Defined in: [packages/pesa/src/errors.ts:52](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L52) Thrown when the provider returns an error response (provider error). ## Extends - [`PesaError`](PesaError) ## Constructors ### Constructor ```ts new PesaProviderError( message, statusCode, providerRaw?): PesaProviderError; ``` Defined in: [packages/pesa/src/errors.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L53) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | | `statusCode` | `number` | | `providerRaw?` | `unknown` | #### Returns `PesaProviderError` #### Overrides [`PesaError`](PesaError).[`constructor`](PesaError.md#constructor) ## Properties | Property | Modifier | Type | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [`PesaError`](PesaError).[`code`](PesaError.md#code) | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | | `providerRaw?` | `readonly` | `unknown` | - | [packages/pesa/src/errors.ts:56](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L56) | | `statusCode` | `readonly` | `number` | - | [packages/pesa/src/errors.ts:55](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L55) | --- # Class: PesaUnsupportedError Defined in: [packages/pesa/src/errors.ts:20](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L20) Thrown when a provider does not implement an optional operation. ## Extends - [`PesaError`](PesaError) ## Constructors ### Constructor ```ts new PesaUnsupportedError(message): PesaUnsupportedError; ``` Defined in: [packages/pesa/src/errors.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L21) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | #### Returns `PesaUnsupportedError` #### Overrides [`PesaError`](PesaError).[`constructor`](PesaError.md#constructor) ## Properties | Property | Modifier | Type | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [`PesaError`](PesaError).[`code`](PesaError.md#code) | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | --- # Class: PesaValidationError Defined in: [packages/pesa/src/errors.ts:44](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L44) Thrown when payload validation fails (client error). ## Extends - [`PesaError`](PesaError) ## Constructors ### Constructor ```ts new PesaValidationError(message): PesaValidationError; ``` Defined in: [packages/pesa/src/errors.ts:45](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L45) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | #### Returns `PesaValidationError` #### Overrides [`PesaError`](PesaError).[`constructor`](PesaError.md#constructor) ## Properties | Property | Modifier | Type | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [`PesaError`](PesaError).[`code`](PesaError.md#code) | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | --- # Class: PesaWebhookError Defined in: [packages/pesa/src/errors.ts:28](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L28) Thrown when a webhook fails signature verification. ## Extends - [`PesaError`](PesaError) ## Constructors ### Constructor ```ts new PesaWebhookError(message): PesaWebhookError; ``` Defined in: [packages/pesa/src/errors.ts:29](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L29) #### Parameters | Parameter | Type | | ------ | ------ | | `message` | `string` | #### Returns `PesaWebhookError` #### Overrides [`PesaError`](PesaError).[`constructor`](PesaError.md#constructor) ## Properties | Property | Modifier | Type | Inherited from | Defined in | | ------ | ------ | ------ | ------ | ------ | | `code` | `readonly` | `string` | [`PesaError`](PesaError).[`code`](PesaError.md#code) | [packages/pesa/src/errors.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/errors.ts#L12) | --- # Function: createPesa() ```ts function createPesa(config): PesaInstance; ``` Defined in: [packages/pesa/src/pesa.ts:235](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L235) The single entry point for the entire Bora Pesa SDK. ## Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `config` | [`PesaConfig`](../interfaces/PesaConfig) | — only `provider` is required. Everything else has sensible defaults (in-memory event store, no plugins). | ## Returns [`PesaInstance`](../interfaces/PesaInstance) ## Since 0.1.0 Returns a fully configured [PesaInstance](../interfaces/PesaInstance) with provider logic, plugin pipeline, and event store wired together. ## Example **Production setup with Selcom** ```ts import { createPesa } from '@borapesa/pesa'; import { SelcomPaymentProvider } from '@borapesa/selcom'; import { retryPlugin, loggingPlugin } from '@borapesa/pesa/plugins'; const pesa = createPesa({ provider: new SelcomPaymentProvider({ apiKey: process.env.SELCOM_API_KEY!, apiSecret: process.env.SELCOM_API_SECRET!, vendor: process.env.SELCOM_VENDOR!, pin: process.env.SELCOM_PIN!, baseUrl: 'https://apigw.selcommobile.com', }), plugins: [ retryPlugin({ maxAttempts: 3, backoff: 'exponential' }), loggingPlugin({ level: 'info' }), ], }); ``` **Local development with BogusProvider** ```ts import { createPesa } from '@borapesa/pesa'; import { BogusPaymentProvider } from '@borapesa/pesa/testing'; const pesa = createPesa({ provider: new BogusPaymentProvider({ defaultBehavior: 'success', delay: 200, }), }); ``` ## Throws `PesaProviderError` — if the provider config is invalid or unreachable. `PesaValidationError` — if required config fields are missing. --- # Function: createPesaWebhookHandler() ```ts function createPesaWebhookHandler(pesa, basePath?): (request) => Promise; ``` Defined in: [packages/pesa/src/handler.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/handler.ts#L26) Creates a webhook handler — the one route that must be publicly exposed. Mount this behind no auth so providers can POST callbacks: ```ts Bun.serve({ fetch: pesa.mountWebhook }); ``` For order creation and status queries, use `pesa.createOrder()` and `pesa.getPaymentStatus()` in your own routes behind your own auth. ## Parameters | Parameter | Type | Default value | Description | | ------ | ------ | ------ | ------ | | `pesa` | [`PesaHandlerTarget`](../interfaces/PesaHandlerTarget) | `undefined` | - | | `basePath` | `string` | `'/pesa'` | — defaults to `'/pesa'` | ## Returns (`request`) => `Promise`\<`Response`\> --- # Function: normalisePhone() ```ts function normalisePhone(input): string; ``` Defined in: [packages/pesa/src/validate.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/validate.ts#L22) Normalise a Tanzania phone number to canonical MSISDN format (255XXXXXXXXX). Accepts common local formats: "255781000000" → "255781000000" "+255781000000" → "255781000000" "0781000000" → "255781000000" "781000000" → "255781000000" Whitespace, dashes, and parentheses are stripped before validation. The result is validated against the MSISDN regex before returning. ## Parameters | Parameter | Type | | ------ | ------ | | `input` | `string` | ## Returns `string` ## Throws PesaValidationError if the number cannot be coerced to MSISDN. --- # Function: validateCreateOrderPayload() ```ts function validateCreateOrderPayload(payload): void; ``` Defined in: [packages/pesa/src/validate.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/validate.ts#L57) Validate a CreateOrderPayload before forwarding to the provider. Throws PesaValidationError on invalid input. ## Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`CreateOrderPayload`](../interfaces/CreateOrderPayload) | ## Returns `void` --- # Function: validateDisbursePayload() ```ts function validateDisbursePayload(payload): void; ``` Defined in: [packages/pesa/src/validate.ts:87](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/validate.ts#L87) Validate a DisbursePayload before forwarding to the provider. Throws PesaValidationError on invalid input. ## Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`DisbursePayload`](../interfaces/DisbursePayload) | ## Returns `void` --- # @borapesa/pesa ## Classes | Class | Description | | ------ | ------ | | [BasePaymentProvider](classes/BasePaymentProvider) | Abstract base class every provider adapter must implement. | | [MemoryAdapter](classes/MemoryAdapter) | In-memory event store — zero dependencies, perfect for dev and CI. | | [PesaError](classes/PesaError) | Base error class for all Bora Pesa errors. | | [PesaNetworkError](classes/PesaNetworkError) | Thrown when a provider API is unreachable or returns a network error. | | [PesaProviderError](classes/PesaProviderError) | Thrown when the provider returns an error response (provider error). | | [PesaUnsupportedError](classes/PesaUnsupportedError) | Thrown when a provider does not implement an optional operation. | | [PesaValidationError](classes/PesaValidationError) | Thrown when payload validation fails (client error). | | [PesaWebhookError](classes/PesaWebhookError) | Thrown when a webhook fails signature verification. | ## Interfaces | Interface | Description | | ------ | ------ | | [BalanceEntry](interfaces/BalanceEntry) | A single currency balance entry. | | [BalanceResult](interfaces/BalanceResult) | Result of a balance inquiry — returns available balances across all active currencies in the provider's wallet. | | [CancelOrderPayload](interfaces/CancelOrderPayload) | Payload for cancelling a pending or in-progress order. | | [CancelOrderResult](interfaces/CancelOrderResult) | Result returned after cancelling a payment order. | | [CreateOrderPayload](interfaces/CreateOrderPayload) | Payload for creating a payment order. | | [DisbursePayload](interfaces/DisbursePayload) | Payload for sending a disbursement (B2C / wallet-out). | | [DisburseResult](interfaces/DisburseResult) | Result returned after initiating a disbursement. | | [ListOrdersParams](interfaces/ListOrdersParams) | Parameters for listing payment orders. | | [ListOrdersResult](interfaces/ListOrdersResult) | Result returned when listing orders. | | [NameLookupResult](interfaces/NameLookupResult) | Result of a name lookup — resolves the account holder name for a phone number or bank account before disbursing. | | [OrderResult](interfaces/OrderResult) | Result returned after initiating a payment. | | [PaymentEvent](interfaces/PaymentEvent) | Normalized payment event — the **source of truth** for all payment activity. | | [PesaConfig](interfaces/PesaConfig) | Configuration passed to [createPesa](functions/createPesa). | | [PesaDatabaseAdapter](interfaces/PesaDatabaseAdapter) | Database adapter interface for the event store. | | [PesaHandlerTarget](interfaces/PesaHandlerTarget) | Minimal interface for the pesa instance that the handler needs. | | [PesaInstance](interfaces/PesaInstance) | Fully configured payments SDK instance — returned by [createPesa](functions/createPesa). | | [PesaPlugin](interfaces/PesaPlugin) | Plugin lifecycle hooks. | | [PreviewResult](interfaces/PreviewResult) | Result of a preview / dry-run validation before committing an action. | | [RefundResult](interfaces/RefundResult) | Result returned after initiating a refund. | | [RequestContext](interfaces/RequestContext) | Context passed to beforeRequest hooks. Allows plugins to inspect and modify the outgoing request. | | [ResponseContext](interfaces/ResponseContext) | Context passed to afterResponse hooks. Allows plugins to inspect the provider response and decide on retries. | ## Type Aliases | Type Alias | Description | | ------ | ------ | | [Currency](type-aliases/Currency) | Supported currencies. | | [MobileNetwork](type-aliases/MobileNetwork) | Supported mobile money networks for disbursement (B2C payouts). | | [PaymentEventType](type-aliases/PaymentEventType) | Event types emitted after webhook verification and persistence. | | [PaymentStatus](type-aliases/PaymentStatus) | Payment lifecycle statuses. | | [ProviderName](type-aliases/ProviderName) | All supported payment providers. | | [TZSAmount](type-aliases/TZSAmount) | TZS amount as a whole integer. `15000` = TZS 15,000. | ## Functions | Function | Description | | ------ | ------ | | [createPesa](functions/createPesa) | The single entry point for the entire Bora Pesa SDK. | | [createPesaWebhookHandler](functions/createPesaWebhookHandler) | Creates a webhook handler — the one route that must be publicly exposed. | | [normalisePhone](functions/normalisePhone) | Normalise a Tanzania phone number to canonical MSISDN format (255XXXXXXXXX). | | [validateCreateOrderPayload](functions/validateCreateOrderPayload) | Validate a CreateOrderPayload before forwarding to the provider. Throws PesaValidationError on invalid input. | | [validateDisbursePayload](functions/validateDisbursePayload) | Validate a DisbursePayload before forwarding to the provider. Throws PesaValidationError on invalid input. | --- # Interface: BalanceEntry Defined in: [packages/pesa/src/types/account.ts:31](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L31) A single currency balance entry. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `amount` | `number` | Available amount in that currency. | [packages/pesa/src/types/account.ts:35](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L35) | | `currency` | `string` | ISO 4217 currency code (e.g., `"TZS"`, `"USD"`). | [packages/pesa/src/types/account.ts:33](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L33) | --- # Interface: BalanceResult Defined in: [packages/pesa/src/types/account.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L21) Result of a balance inquiry — returns available balances across all active currencies in the provider's wallet. Use `pesa.getBalance()` to verify available funds before initiating disbursements or to display wallet health in dashboards. ## Since 0.2.0 ## Example ```ts if (pesa.getBalance) { const { balances } = await pesa.getBalance(); const tzsBalance = balances.find((b) => b.currency === 'TZS'); console.log(`Available: TZS ${tzsBalance?.amount ?? 0}`); } ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `balances` | [`BalanceEntry`](BalanceEntry)[] | Per-currency balance entries. | [packages/pesa/src/types/account.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L23) | | `raw?` | `unknown` | Raw provider response. | [packages/pesa/src/types/account.ts:25](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/account.ts#L25) | --- # Interface: CancelOrderPayload Defined in: [packages/pesa/src/types/order.ts:126](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L126) Payload for cancelling a pending or in-progress order. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `orderId` | `string` | The provider-assigned order ID. | [packages/pesa/src/types/order.ts:128](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L128) | --- # Interface: CancelOrderResult Defined in: [packages/pesa/src/types/order.ts:132](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L132) Result returned after cancelling a payment order. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `cancelled` | `boolean` | Whether the cancellation succeeded. | [packages/pesa/src/types/order.ts:136](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L136) | | `message?` | `string` | Optional human-readable message from the provider. | [packages/pesa/src/types/order.ts:138](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L138) | | `orderId` | `string` | The cancelled order ID. | [packages/pesa/src/types/order.ts:134](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L134) | | `raw?` | `unknown` | Raw provider response. | [packages/pesa/src/types/order.ts:140](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L140) | --- # Interface: CreateOrderPayload Defined in: [packages/pesa/src/types/order.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L53) Payload for creating a payment order. Pass this to [PesaInstance.createOrder](PesaInstance.md#createorder) to initiate a payment. The SDK validates required fields before forwarding to the provider. ## Example ```ts const order = await pesa.createOrder({ amount: 15000, currency: 'TZS', reference: 'order_abc123', customer: { name: 'Juma Ali', phone: '255712345678', email: 'juma@example.com', }, description: 'Monthly subscription', }); ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `amount` | `number` | Amount in whole TZS. 15000 = TZS 15,000. Must be > 0. | [packages/pesa/src/types/order.ts:55](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L55) | | `currency` | [`Currency`](../type-aliases/Currency) | Currency code. Currently only `'TZS'`. | [packages/pesa/src/types/order.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L57) | | `customer` | \{ `email?`: `string`; `name`: `string`; `phone`: `string`; \} | Customer details. | [packages/pesa/src/types/order.ts:66](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L66) | | `customer.email?` | `string` | Customer's email address (optional). | [packages/pesa/src/types/order.ts:75](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L75) | | `customer.name` | `string` | Customer's full name. | [packages/pesa/src/types/order.ts:68](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L68) | | `customer.phone` | `string` | Mobile money phone number in MSISDN format: `255XXXXXXXXX`. Local formats like `07XX` are rejected. | [packages/pesa/src/types/order.ts:73](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L73) | | `description?` | `string` | Optional human-readable description of the order. | [packages/pesa/src/types/order.ts:64](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L64) | | `metadata?` | `Record`\<`string`, `unknown`\> | Arbitrary metadata attached to the order. | [packages/pesa/src/types/order.ts:83](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L83) | | `redirectUrl?` | `string` | Required for redirect-based providers (DPO, Pesapal). URL the customer is sent to after completing payment. | [packages/pesa/src/types/order.ts:81](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L81) | | `reference` | `string` | Your internal order identifier. Must be unique. Used for idempotency — the same reference won't be charged twice. | [packages/pesa/src/types/order.ts:62](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L62) | --- # Interface: DisbursePayload Defined in: [packages/pesa/src/types/disbursement.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L36) Payload for sending a disbursement (B2C / wallet-out). Pass this to [PesaInstance.disburse](PesaInstance.md#disburse) to send money to a customer's mobile money wallet or bank account. **Mobile money** — provide `recipient.phone`. **Bank payout** — provide `recipient.accountNumber` + `recipient.bic`. ## Since 0.1.0 (mobile money), 0.2.0 (bank payout fields) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `amount` | `number` | Amount in whole TZS. Must be > 0. | [packages/pesa/src/types/disbursement.ts:38](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L38) | | `currency` | [`Currency`](../type-aliases/Currency) | Currency code. Currently only `'TZS'`. | [packages/pesa/src/types/disbursement.ts:40](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L40) | | `recipient` | \{ `accountNumber?`: `string`; `bic?`: `string`; `name?`: `string`; `network?`: [`MobileNetwork`](../type-aliases/MobileNetwork); `phone?`: `string`; `transferType?`: `BankTransferType`; \} | Recipient details. | [packages/pesa/src/types/disbursement.ts:42](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L42) | | `recipient.accountNumber?` | `string` | Bank account number (for bank payouts). | [packages/pesa/src/types/disbursement.ts:50](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L50) | | `recipient.bic?` | `string` | Bank identifier code — fetch via `getBanks()` on supported providers. | [packages/pesa/src/types/disbursement.ts:52](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L52) | | `recipient.name?` | `string` | Recipient's full name (optional but recommended). | [packages/pesa/src/types/disbursement.ts:46](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L46) | | `recipient.network?` | [`MobileNetwork`](../type-aliases/MobileNetwork) | Target mobile money network. | [packages/pesa/src/types/disbursement.ts:48](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L48) | | `recipient.phone?` | `string` | Mobile money phone number in MSISDN format: `255XXXXXXXXX`. | [packages/pesa/src/types/disbursement.ts:44](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L44) | | `recipient.transferType?` | `BankTransferType` | Transfer type for bank payouts: `"ACH"` (default) or `"RTGS"`. | [packages/pesa/src/types/disbursement.ts:54](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L54) | | `reference` | `string` | Your internal reference. Must be unique. | [packages/pesa/src/types/disbursement.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L57) | | `remarks?` | `string` | Optional remarks / narration for the payout. | [packages/pesa/src/types/disbursement.ts:59](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L59) | --- # Interface: DisburseResult Defined in: [packages/pesa/src/types/disbursement.ts:79](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L79) Result returned after initiating a disbursement. ## Example ```ts const result = await pesa.disburse({ amount: 50000, currency: 'TZS', reference: 'payout_001', recipient: { phone: '255754321098', network: 'MPESA' }, }); if (result.status === 'SUCCESS') { console.log(`Disbursement ${result.disbursementId} sent`); } ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `disbursementId` | `string` | Provider-assigned disbursement ID. | [packages/pesa/src/types/disbursement.ts:81](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L81) | | `raw?` | `unknown` | Raw provider response. Escape hatch. | [packages/pesa/src/types/disbursement.ts:92](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L92) | | `reference` | `string` | Your reference, echoed back. | [packages/pesa/src/types/disbursement.ts:83](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L83) | | `status` | `"SUCCESS"` \| `"FAILED"` \| `"QUEUED"` | Disbursement status. - `SUCCESS` — funds sent - `QUEUED` — processing, poll for updates - `FAILED` — definitively failed | [packages/pesa/src/types/disbursement.ts:90](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L90) | --- # Interface: ListOrdersParams Defined in: [packages/pesa/src/types/order.ts:144](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L144) Parameters for listing payment orders. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `fromDate?` | `Date` | Filter orders created on or after this date. | [packages/pesa/src/types/order.ts:146](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L146) | | `limit?` | `number` | Maximum number of orders to return. | [packages/pesa/src/types/order.ts:150](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L150) | | `offset?` | `number` | Number of orders to skip (for pagination). | [packages/pesa/src/types/order.ts:152](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L152) | | `toDate?` | `Date` | Filter orders created on or before this date. | [packages/pesa/src/types/order.ts:148](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L148) | --- # Interface: ListOrdersResult Defined in: [packages/pesa/src/types/order.ts:156](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L156) Result returned when listing orders. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `orders` | \{ `amount`: `number`; `createdAt`: `Date`; `currency`: [`Currency`](../type-aliases/Currency); `orderId`: `string`; `raw?`: `unknown`; `reference`: `string`; `status`: [`PaymentStatus`](../type-aliases/PaymentStatus); \}[] | Matching orders. | [packages/pesa/src/types/order.ts:158](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L158) | | `total` | `number` | Total number of matching orders (before limit/offset). | [packages/pesa/src/types/order.ts:168](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L168) | --- # Interface: NameLookupResult Defined in: [packages/pesa/src/types/preview.ts:47](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L47) Result of a name lookup — resolves the account holder name for a phone number or bank account before disbursing. ## Example ```ts if (pesa.getNameLookup) { const lookup = await pesa.getNameLookup('255712345678'); if (lookup.found) { console.log(`Account: ${lookup.accountName}`); } } ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `accountName?` | `string` | Account holder's name, if found. | [packages/pesa/src/types/preview.ts:51](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L51) | | `accountNumber?` | `string` | Account number / phone number. | [packages/pesa/src/types/preview.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L53) | | `found` | `boolean` | Whether the account was found. | [packages/pesa/src/types/preview.ts:49](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L49) | | `message?` | `string` | Optional human-readable message. | [packages/pesa/src/types/preview.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L57) | | `provider?` | `string` | Provider or network name (e.g., 'MPESA', 'CRDB'). | [packages/pesa/src/types/preview.ts:55](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L55) | | `raw?` | `unknown` | Raw provider response. | [packages/pesa/src/types/preview.ts:59](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L59) | --- # Interface: OrderResult Defined in: [packages/pesa/src/types/order.ts:104](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L104) Result returned after initiating a payment. The shape varies by provider. Redirect-based providers (DPO, Pesapal) return `checkoutUrl`. USSD push providers (Selcom, ClickPesa) set `ussdPushInitiated: true`. ## Example ```ts const order = await pesa.createOrder({ ... }); if (order.checkoutUrl) { // Redirect-based flow: send customer to the URL return redirect(order.checkoutUrl); } // USSD push flow: customer receives a PIN prompt on their phone ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `checkoutUrl?` | `string` | Redirect URL for DPO / Pesapal redirect flows. | [packages/pesa/src/types/order.ts:115](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L115) | | `orderId` | `string` | Provider-assigned transaction ID. Use this to query status via [PesaInstance.getPaymentStatus](PesaInstance.md#getpaymentstatus). | [packages/pesa/src/types/order.ts:109](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L109) | | `raw?` | `unknown` | Raw provider response. **Escape hatch — never rely on this.** Use the normalized fields instead. | [packages/pesa/src/types/order.ts:122](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L122) | | `reference` | `string` | Your reference, echoed back. | [packages/pesa/src/types/order.ts:111](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L111) | | `status` | [`PaymentStatus`](../type-aliases/PaymentStatus) | Current payment status. | [packages/pesa/src/types/order.ts:113](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L113) | | `ussdPushInitiated?` | `boolean` | Whether a USSD push was initiated (Selcom / MNO push flows). | [packages/pesa/src/types/order.ts:117](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L117) | --- # Interface: PaymentEvent Defined in: [packages/pesa/src/types/event.ts:47](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L47) Normalized payment event — the **source of truth** for all payment activity. Every webhook received and verified is parsed by the provider adapter, normalized into a `PaymentEvent`, persisted to the event store, and emitted to registered handlers. ## Example ```ts // Accessing event data in a handler pesa.on('PAYMENT_SUCCESS', (event) => { console.log(`Payment ${event.reference} succeeded`); console.log(`Amount: TZS ${event.amount}`); console.log(`Provider: ${event.provider}`); }); ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `amount` | `number` | Amount in whole TZS. | [packages/pesa/src/types/event.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L57) | | `currency` | [`Currency`](../type-aliases/Currency) | Currency code. | [packages/pesa/src/types/event.ts:59](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L59) | | `id` | `string` | UUID generated by the SDK. | [packages/pesa/src/types/event.ts:49](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L49) | | `metadata?` | `Record`\<`string`, `unknown`\> | Arbitrary metadata attached to the event. | [packages/pesa/src/types/event.ts:67](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L67) | | `orderId` | `string` | Provider-assigned transaction ID. | [packages/pesa/src/types/event.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L53) | | `provider` | [`ProviderName`](../type-aliases/ProviderName) | Which provider processed this payment. | [packages/pesa/src/types/event.ts:63](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L63) | | `raw?` | `unknown` | Raw provider webhook payload. Escape hatch — prefer normalized fields. | [packages/pesa/src/types/event.ts:69](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L69) | | `reference` | `string` | Your merchant reference. | [packages/pesa/src/types/event.ts:55](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L55) | | `status` | [`PaymentStatus`](../type-aliases/PaymentStatus) | Normalized payment status. | [packages/pesa/src/types/event.ts:61](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L61) | | `timestamp` | `Date` | When the event occurred. | [packages/pesa/src/types/event.ts:65](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L65) | | `type` | [`PaymentEventType`](../type-aliases/PaymentEventType) | Event type (PAYMENT_SUCCESS, DISBURSEMENT_FAILED, etc.). | [packages/pesa/src/types/event.ts:51](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L51) | --- # Interface: PesaConfig Defined in: [packages/pesa/src/types/config.ts:35](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/config.ts#L35) Configuration passed to [createPesa](../functions/createPesa). Only `provider` is required. Everything else ships with sensible defaults: - In-memory event store (lost on restart — swap to a persistent adapter for production) - No plugins ## Example ```ts import { createPesa } from '@borapesa/pesa'; import { SelcomPaymentProvider } from '@borapesa/selcom'; import { retryPlugin, loggingPlugin } from '@borapesa/pesa/plugins'; const pesa = createPesa({ provider: new SelcomPaymentProvider({ apiKey: process.env.SELCOM_API_KEY!, apiSecret: process.env.SELCOM_API_SECRET!, vendor: process.env.SELCOM_VENDOR!, pin: process.env.SELCOM_PIN!, baseUrl: 'https://apigw.selcommobile.com', }), plugins: [ retryPlugin({ maxAttempts: 3 }), loggingPlugin({ level: 'info' }), ], // Override for production: // db: new SQLiteAdapter({ path: './pesa.db' }), }); ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `basePath?` | `string` | Base path for the built-in webhook handler (`pesa.mountWebhook`). The handler serves a single route: - `POST {basePath}/webhook` — receive provider webhooks For order creation and status queries, use [PesaInstance.createOrder](PesaInstance.md#createorder) and [PesaInstance.getPaymentStatus](PesaInstance.md#getpaymentstatus) in your own routes behind your own auth middleware. **Default** `'/pesa'` | [packages/pesa/src/types/config.ts:57](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/config.ts#L57) | | `db?` | [`PesaDatabaseAdapter`](PesaDatabaseAdapter) | Database adapter for the event store. Defaults to an in-memory store (lost on restart). Swap to the `@borapesa/sqlite` adapter for production deployments, or implement the [PesaDatabaseAdapter](PesaDatabaseAdapter) interface for your own database. | [packages/pesa/src/types/config.ts:76](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/config.ts#L76) | | `plugins?` | [`PesaPlugin`](PesaPlugin)[] | Plugin array. Plugins are composed **in order**. Built-in plugins available from `@borapesa/pesa/plugins`: - `retryPlugin` — exponential/linear/fixed backoff - `idempotencyPlugin` — prevents duplicate charges - `loggingPlugin` — structured logging with PII redaction | [packages/pesa/src/types/config.ts:67](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/config.ts#L67) | | `provider` | [`BasePaymentProvider`](../classes/BasePaymentProvider) | The payment provider adapter. Choose from `@borapesa/selcom`, `@borapesa/clickpesa`, `@borapesa/azampay` (DPO and Pesapal are planned), or use the built-in `BogusPaymentProvider` for local development. | [packages/pesa/src/types/config.ts:43](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/config.ts#L43) | --- # Interface: PesaDatabaseAdapter Defined in: [packages/pesa/src/db/adapter.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/adapter.ts#L10) Database adapter interface for the event store. The default is an in-memory adapter (zero deps, dev/CI ready). Swap for `@borapesa/sqlite`, or implement your own adapter via the `db` field in PesaConfig — the four methods work with any database. ## Methods ### getEvent() ```ts getEvent(id): Promise; ``` Defined in: [packages/pesa/src/db/adapter.ts:15](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/adapter.ts#L15) Retrieve a single event by its UUID. #### Parameters | Parameter | Type | | ------ | ------ | | `id` | `string` | #### Returns `Promise`\<[`PaymentEvent`](PaymentEvent) \| `null`\> *** ### getEventsByOrderId() ```ts getEventsByOrderId(orderId): Promise; ``` Defined in: [packages/pesa/src/db/adapter.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/adapter.ts#L21) Retrieve all events for a given provider order ID. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`PaymentEvent`](PaymentEvent)[]\> *** ### getEventsByReference() ```ts getEventsByReference(reference): Promise; ``` Defined in: [packages/pesa/src/db/adapter.ts:18](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/adapter.ts#L18) Retrieve all events for a given merchant reference. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<[`PaymentEvent`](PaymentEvent)[]\> *** ### saveEvent() ```ts saveEvent(event): Promise; ``` Defined in: [packages/pesa/src/db/adapter.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/db/adapter.ts#L12) Persist a verified PaymentEvent. #### Parameters | Parameter | Type | | ------ | ------ | | `event` | [`PaymentEvent`](PaymentEvent) | #### Returns `Promise`\<`void`\> --- # Interface: PesaHandlerTarget Defined in: [packages/pesa/src/handler.ts:7](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/handler.ts#L7) Minimal interface for the pesa instance that the handler needs. ## Methods ### handleWebhook() ```ts handleWebhook(rawBody, headers): Promise; ``` Defined in: [packages/pesa/src/handler.ts:8](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/handler.ts#L8) #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<`void`\> *** ### on() ```ts on(event, handler): void; ``` Defined in: [packages/pesa/src/handler.ts:9](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/handler.ts#L9) #### Parameters | Parameter | Type | | ------ | ------ | | `event` | [`PaymentEventType`](../type-aliases/PaymentEventType) | | `handler` | (`event`) => `void` \| `Promise`\<`void`\> | #### Returns `void` --- # Interface: PesaInstance Defined in: [packages/pesa/src/pesa.ts:89](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L89) Fully configured payments SDK instance — returned by [createPesa](../functions/createPesa). ## Since 0.1.0 ## Core operations ```ts // Initiate a payment const order = await pesa.createOrder({ amount: 15000, currency: 'TZS', reference: 'order_abc', customer: { name: 'Juma Ali', phone: '255712345678' }, }); // Poll status const status = await pesa.getPaymentStatus(order.orderId); // Send money to a customer await pesa.disburse({ amount: 50000, currency: 'TZS', reference: 'payout_xyz', recipient: { phone: '255754321098', network: 'MPESA' }, }); ``` ## Events ```ts // React to verified + persisted payment events pesa.on('PAYMENT_SUCCESS', async (event) => { await db.orders.update({ id: event.reference, status: 'paid', }); }); ``` ## Optional operations (feature detection) ```ts // Not all providers support these. Check before calling. if (pesa.getBalance) await pesa.getBalance(); if (pesa.refund) await pesa.refund('order_123', 5000); if (pesa.previewOrder) await pesa.previewOrder({ ... }); if (pesa.validateCredentials) await pesa.validateCredentials(); ``` ## HTTP mount ```ts // Mount the webhook handler — the one route that must be public Bun.serve({ fetch: pesa.mountWebhook }); // For orders/status, use pesa.createOrder() and pesa.getPaymentStatus() // in your own routes behind your own auth middleware. ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `mountWebhook` | (`request`) => `Promise`\<`Response`\> | Webhook handler — mount this publicly so providers can POST callbacks. Route: `POST {basePath}/webhook` For order creation and status queries, use [createOrder](#createorder) and [getPaymentStatus](#getpaymentstatus) in your own routes behind your own auth. | [packages/pesa/src/pesa.ts:183](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L183) | | `provider` | [`BasePaymentProvider`](../classes/BasePaymentProvider) | The underlying provider adapter. | [packages/pesa/src/pesa.ts:173](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L173) | ## Methods ### cancelOrder()? ```ts optional cancelOrder(orderId): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:150](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L150) Cancel a pending or in-progress order. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`CancelOrderResult`](CancelOrderResult)\> *** ### createOrder() ```ts createOrder(payload): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:102](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L102) Initiate a checkout / USSD push / redirect. The SDK validates the payload before forwarding to the provider (amount > 0, valid MSISDN phone, non-empty reference). #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`CreateOrderPayload`](CreateOrderPayload) | #### Returns `Promise`\<[`OrderResult`](OrderResult)\> #### Throws `PesaValidationError` — if the payload is invalid. `PesaNetworkError` — if the provider is unreachable. `PesaProviderError` — if the provider returns an error. *** ### disburse() ```ts disburse(payload): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:124](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L124) B2C / wallet-out disbursement. The SDK validates the payload before forwarding to the provider. Returns a [DisburseResult](DisburseResult) whose `status` is `'QUEUED'` (processing — poll for updates), `'SUCCESS'`, or `'FAILED'`. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`DisbursePayload`](DisbursePayload) | #### Returns `Promise`\<[`DisburseResult`](DisburseResult)\> #### Throws `PesaValidationError` — if the payload is invalid. `PesaNetworkError` — if the provider is unreachable. `PesaProviderError` — if the provider returns an error. *** ### getBalance()? ```ts optional getBalance(): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:156](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L156) Retrieve wallet balances across currencies. `undefined` if unsupported. #### Returns `Promise`\<[`BalanceResult`](BalanceResult)\> *** ### getNameLookup()? ```ts optional getNameLookup(phoneOrAccount): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:165](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L165) Resolve account holder name. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `phoneOrAccount` | `string` | #### Returns `Promise`\<[`NameLookupResult`](NameLookupResult)\> *** ### getPaymentStatus() ```ts getPaymentStatus(orderId): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:110](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L110) Poll or fetch current payment status. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`PaymentStatus`](../type-aliases/PaymentStatus)\> #### Throws `PesaNetworkError` — if the provider is unreachable. `PesaProviderError` — if the provider returns an error. *** ### handleWebhook() ```ts handleWebhook(rawBody, headers): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:132](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L132) Handle an incoming webhook. Called by framework adapters. Flow: provider verification → UUID assignment → plugin hooks → event persistence → user-registered handler emission. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<`void`\> *** ### listOrders()? ```ts optional listOrders(params): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:168](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L168) List payment orders. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | [`ListOrdersParams`](ListOrdersParams) | #### Returns `Promise`\<[`ListOrdersResult`](ListOrdersResult)\> *** ### on() ```ts on(event, handler): void; ``` Defined in: [packages/pesa/src/pesa.ts:142](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L142) Register a handler for a payment event type. Handlers fire **after** the event is verified and persisted. Multiple handlers can be registered for the same event type. #### Parameters | Parameter | Type | | ------ | ------ | | `event` | [`PaymentEventType`](../type-aliases/PaymentEventType) | | `handler` | (`event`) => `void` \| `Promise`\<`void`\> | #### Returns `void` *** ### previewDisburse()? ```ts optional previewDisburse(payload): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:162](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L162) Preview / dry-run a disbursement. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`DisbursePayload`](DisbursePayload) | #### Returns `Promise`\<[`PreviewResult`](PreviewResult)\> *** ### previewOrder()? ```ts optional previewOrder(payload): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:159](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L159) Preview / dry-run a payment. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | [`CreateOrderPayload`](CreateOrderPayload) | #### Returns `Promise`\<[`PreviewResult`](PreviewResult)\> *** ### refund()? ```ts optional refund(orderId, amount?): Promise; ``` Defined in: [packages/pesa/src/pesa.ts:147](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L147) Refund a completed payment. `undefined` if unsupported. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | | `amount?` | `number` | #### Returns `Promise`\<[`RefundResult`](RefundResult)\> *** ### validateCredentials()? ```ts optional validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [packages/pesa/src/pesa.ts:153](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/pesa.ts#L153) Validate provider credentials (health check). `undefined` if unsupported. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> --- # Interface: PesaPlugin Defined in: [packages/pesa/src/plugins/types.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L36) Plugin lifecycle hooks. Plugins are plain objects passed in the `plugins` array of PesaConfig. They are composed in order at createPesa() time. No class inheritance. ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `afterResponse?` | (`ctx`) => `Promise`\<[`ResponseContext`](ResponseContext)\> | Called after each response from a payment provider. Plugins can inspect the response and set `ctx.retry = true` to trigger a retry (handled by the retry plugin). | [packages/pesa/src/plugins/types.ts:51](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L51) | | `beforeRequest?` | (`ctx`) => `Promise`\<[`RequestContext`](RequestContext)\> | Called before each outgoing request to a payment provider. Plugins can modify the request context (e.g., add idempotency keys). | [packages/pesa/src/plugins/types.ts:44](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L44) | | `init?` | (`pesa`) => `void` | Called once at startup. Receives the pesa instance for extension. | [packages/pesa/src/plugins/types.ts:80](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L80) | | `name` | `string` | Unique plugin name (used for logging and debugging). | [packages/pesa/src/plugins/types.ts:38](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L38) | | `onError?` | (`error`, `ctx`) => `Promise`\<[`ResponseContext`](ResponseContext) \| `undefined`\> | Called when a provider request throws an error. Plugins can inspect the error and set `ctx.retry = true` + a delay in `ctx.metadata.retryDelayMs` to trigger a retry. If no plugin sets `retry = true`, the error is re-thrown. **Since** 0.6.0 | [packages/pesa/src/plugins/types.ts:62](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L62) | | `onPaymentEvent?` | (`event`) => `Promise`\<`void`\> | Called **before** a verified PaymentEvent is persisted to the event store. Throw to reject the event — it will bubble up as a webhook error and the event will not be saved. Do **not** query the event store for this event here — it hasn't been persisted yet. Use for: webhook deduplication, custom verification, spam filtering. For side effects after persistence, register a [PesaInstance.on](PesaInstance.md#on) handler instead. | [packages/pesa/src/plugins/types.ts:75](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L75) | --- # Interface: PreviewResult Defined in: [packages/pesa/src/types/preview.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L22) Result of a preview / dry-run validation before committing an action. Use `pesa.previewOrder()` or `pesa.previewDisburse()` to validate payloads and check fees before initiating real transactions. ## Example ```ts if (pesa.previewOrder) { const preview = await pesa.previewOrder({ amount: 15000, currency: 'TZS', reference: 'pre_001', customer: { name: 'Juma', phone: '255712345678' }, }); console.log(`Fee: TZS ${preview.fee}`); console.log(`Total: TZS ${15000 + (preview.fee ?? 0)}`); } ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `fee?` | `number` | Expected transaction fee in TZS, if available. | [packages/pesa/src/types/preview.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L26) | | `message?` | `string` | Optional human-readable message (e.g., error details). | [packages/pesa/src/types/preview.ts:28](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L28) | | `raw?` | `unknown` | Raw provider response. | [packages/pesa/src/types/preview.ts:30](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L30) | | `valid` | `boolean` | Whether the payload is valid. | [packages/pesa/src/types/preview.ts:24](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/preview.ts#L24) | --- # Interface: RefundResult Defined in: [packages/pesa/src/types/refund.ts:19](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L19) Result returned after initiating a refund. Not all providers support refunds. Check capability via `pesa.refund !== undefined` before calling. ## Example ```ts if (pesa.refund) { const result = await pesa.refund('order_123', 5000); if (result.status === 'SUCCESS') { console.log(`Refund ${result.refundId} processed`); } } ``` ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `amount` | `number` | Amount refunded in whole TZS. | [packages/pesa/src/types/refund.ts:25](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L25) | | `message?` | `string` | Optional human-readable message from the provider. | [packages/pesa/src/types/refund.ts:34](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L34) | | `orderId` | `string` | The original order ID being refunded. | [packages/pesa/src/types/refund.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L23) | | `raw?` | `unknown` | Raw provider response. | [packages/pesa/src/types/refund.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L36) | | `refundId` | `string` | Provider-assigned refund ID. | [packages/pesa/src/types/refund.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L21) | | `status` | `"SUCCESS"` \| `"FAILED"` \| `"QUEUED"` | Refund status. - `SUCCESS` — refund processed - `QUEUED` — refund initiated, poll for updates - `FAILED` — refund failed | [packages/pesa/src/types/refund.ts:32](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/refund.ts#L32) | --- # Interface: RequestContext Defined in: [packages/pesa/src/plugins/types.ts:10](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L10) Context passed to beforeRequest hooks. Allows plugins to inspect and modify the outgoing request. ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `headers` | `Record`\<`string`, `string`\> | [packages/pesa/src/plugins/types.ts:13](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L13) | | `metadata` | `Record`\<`string`, `unknown`\> | [packages/pesa/src/plugins/types.ts:14](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L14) | | `operation` | `"createOrder"` \| `"disburse"` \| `"refund"` \| `"cancelOrder"` | [packages/pesa/src/plugins/types.ts:11](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L11) | | `payload` | \| [`CreateOrderPayload`](CreateOrderPayload) \| [`DisbursePayload`](DisbursePayload) \| `Record`\<`string`, `unknown`\> | [packages/pesa/src/plugins/types.ts:12](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L12) | --- # Interface: ResponseContext Defined in: [packages/pesa/src/plugins/types.ts:21](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L21) Context passed to afterResponse hooks. Allows plugins to inspect the provider response and decide on retries. ## Properties | Property | Type | Defined in | | ------ | ------ | ------ | | `durationMs` | `number` | [packages/pesa/src/plugins/types.ts:25](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L25) | | `metadata` | `Record`\<`string`, `unknown`\> | [packages/pesa/src/plugins/types.ts:27](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L27) | | `operation` | `"createOrder"` \| `"disburse"` \| `"refund"` \| `"cancelOrder"` | [packages/pesa/src/plugins/types.ts:22](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L22) | | `payload` | \| [`CreateOrderPayload`](CreateOrderPayload) \| [`DisbursePayload`](DisbursePayload) \| `Record`\<`string`, `unknown`\> | [packages/pesa/src/plugins/types.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L23) | | `result` | \| [`OrderResult`](OrderResult) \| [`DisburseResult`](DisburseResult) \| `Record`\<`string`, `unknown`\> | [packages/pesa/src/plugins/types.ts:24](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L24) | | `retry` | `boolean` | [packages/pesa/src/plugins/types.ts:26](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/plugins/types.ts#L26) | --- # Type Alias: Currency ```ts type Currency = "TZS" | "USD"; ``` Defined in: [packages/pesa/src/types/core.ts:49](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/core.ts#L49) Supported currencies. Extensible via module augmentation. Currently only `'TZS'` is fully supported. `'USD'` is available experimentally via ClickPesa card payments but multi-currency is not yet a stable v1 feature. ## Since 0.1.0 — `'TZS'` ## Example ```ts // Future expansion: // module augmentation in your app to add KES declare module '@borapesa/pesa' { export type Currency = 'TZS' | 'USD' | 'KES'; } ``` --- # Type Alias: MobileNetwork ```ts type MobileNetwork = "MPESA" | "TIGOPESA" | "AIRTELMONEY" | "HALOPESA" | "AZAMPESA"; ``` Defined in: [packages/pesa/src/types/disbursement.ts:20](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/disbursement.ts#L20) Supported mobile money networks for disbursement (B2C payouts). ## Example ```ts await pesa.disburse({ amount: 50000, currency: 'TZS', reference: 'payout_001', recipient: { phone: '255754321098', name: 'Juma Ali', network: 'MPESA', }, }); ``` --- # Type Alias: PaymentEventType ```ts type PaymentEventType = | "PAYMENT_SUCCESS" | "PAYMENT_FAILED" | "PAYMENT_PENDING" | "DISBURSEMENT_SUCCESS" | "DISBURSEMENT_FAILED"; ``` Defined in: [packages/pesa/src/types/event.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/event.ts#L23) Event types emitted after webhook verification and persistence. Use these with [PesaInstance.on](../interfaces/PesaInstance.md#on) to react to payment activity: ## Example ```ts pesa.on('PAYMENT_SUCCESS', async (event) => { await db.orders.update({ id: event.reference, status: 'paid', }); }); pesa.on('DISBURSEMENT_FAILED', async (event) => { await notifySupport(event); }); ``` --- # Type Alias: PaymentStatus ```ts type PaymentStatus = | "PENDING" | "PROCESSING" | "SUCCESS" | "FAILED" | "CANCELLED" | "AMBIGUOUS"; ``` Defined in: [packages/pesa/src/types/order.ts:24](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/order.ts#L24) Payment lifecycle statuses. These are the **normalized** statuses the SDK exposes. Each provider adapter maps its native statuses to these values, so application code never has to handle provider-specific status strings. **`AMBIGUOUS`** is a first-class status — it is a real Selcom response meaning the transaction outcome is unknown. Normalizing it to `PENDING` or `FAILED` would lose information. Applications should poll when they receive `AMBIGUOUS`. ## Example ```ts pesa.on('PAYMENT_SUCCESS', (event) => { if (event.status === 'SUCCESS') { // funds confirmed } }); ``` --- # Type Alias: ProviderName ```ts type ProviderName = | "selcom" | "azampay" | "clickpesa" | "snippe" | "dpo" | "pesapal" | "bogus"; ``` Defined in: [packages/pesa/src/types/core.ts:64](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/core.ts#L64) All supported payment providers. Extensible via module augmentation. The `'bogus'` provider is a test double — it doesn't represent a real payment gateway. ## Example ```ts import type { ProviderName } from '@borapesa/pesa'; const provider: ProviderName = 'selcom'; ``` --- # Type Alias: TZSAmount ```ts type TZSAmount = number; ``` Defined in: [packages/pesa/src/types/core.ts:27](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/packages/pesa/src/types/core.ts#L27) TZS amount as a whole integer. `15000` = TZS 15,000. **Never use floats.** TZS has cents (senti) but digital/mobile payment providers don't support fractional amounts on the consumer side. Whole integers prevent floating-point errors and match what every Tanzanian payment API expects. ## Example ```ts // ✅ Correct const amount: TZSAmount = 15000; // ❌ Wrong — will throw PesaValidationError const amount: TZSAmount = 15000.50; ``` --- # Class: SelcomPaymentProvider Defined in: [providers/selcom/src/selcom.ts:87](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L87) ## Extends - `BasePaymentProvider` ## Constructors ### Constructor ```ts new SelcomPaymentProvider(config): SelcomPaymentProvider; ``` Defined in: [providers/selcom/src/selcom.ts:113](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L113) #### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`SelcomConfig`](../interfaces/SelcomConfig) | #### Returns `SelcomPaymentProvider` #### Overrides ```ts BasePaymentProvider.constructor ``` ## Properties | Property | Modifier | Type | Default value | Description | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `name` | `readonly` | `ProviderName` | `'selcom'` | Unique provider identifier. | `BasePaymentProvider.name` | [providers/selcom/src/selcom.ts:88](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L88) | ## Methods ### agentCashout() ```ts agentCashout( msisdn, amount, name?): Promise<{ message: string; reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:868](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L868) Send funds to a customer for cash pickup at any Selcom Huduma agent. The customer dials `*150*50#`, selects Huduma Cashout, enters the agent code and amount to complete the withdrawal. #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `msisdn` | `string` | — customer mobile number (receives the cashout token). | | `amount` | `number` | — amount in TZS. | | `name?` | `string` | — customer name (optional). | #### Returns `Promise`\<\{ `message`: `string`; `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### cancelOrder() ```ts cancelOrder(orderId): Promise<{ cancelled: boolean; message?: string; orderId: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:558](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L558) Cancel a pending or in-progress order. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<\{ `cancelled`: `boolean`; `message?`: `string`; `orderId`: `string`; \}\> #### Throws `PesaUnsupportedError` — if the provider does not support cancellation. #### Overrides ```ts BasePaymentProvider.cancelOrder ``` *** ### checkoutWalletPayment() ```ts checkoutWalletPayment(orderId, msisdn): Promise<{ reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:672](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L672) Trigger a USSD push from an existing checkout order. Use this for in-app payments where the customer is already on your checkout page and you want to trigger a mobile money PIN prompt without redirecting to Selcom's payment gateway. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | | `msisdn` | `string` | #### Returns `Promise`\<\{ `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### createOrder() ```ts createOrder(payload): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:264](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L264) Initiate a checkout / USSD push / redirect. The SDK calls `validateCreateOrderPayload()` before this, so you can assume `amount > 0`, `reference` is non-empty, and `customer.phone` is in MSISDN format. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `CreateOrderPayload` | #### Returns `Promise`\<`OrderResult`\> #### Overrides ```ts BasePaymentProvider.createOrder ``` *** ### deleteStoredCard() ```ts deleteStoredCard(id, gatewayBuyerUuid): Promise<{ message: string; status: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:942](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L942) Delete a stored card token. #### Parameters | Parameter | Type | | ------ | ------ | | `id` | `string` | | `gatewayBuyerUuid` | `string` | #### Returns `Promise`\<\{ `message`: `string`; `status`: `string`; \}\> *** ### disburse() ```ts disburse(payload): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:378](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L378) B2C / wallet-out disbursement. The SDK calls `validateDisbursePayload()` before this. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`DisburseResult`\> #### Overrides ```ts BasePaymentProvider.disburse ``` *** ### fetchStoredCards() ```ts fetchStoredCards(gatewayBuyerUuid, buyerUserid): Promise<{ cards: { cardToken: string; cardType: string; creationDate: string; id: string; maskedCard: string; name: string; }[]; }>; ``` Defined in: [providers/selcom/src/selcom.ts:909](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L909) Fetch stored (tokenized) cards for a buyer. #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `gatewayBuyerUuid` | `string` | — returned from the first create-order call for this buyer (`raw.data[0].gateway_buyer_uuid`). | | `buyerUserid` | `string` | — your internal user ID for the buyer. | #### Returns `Promise`\<\{ `cards`: \{ `cardToken`: `string`; `cardType`: `string`; `creationDate`: `string`; `id`: `string`; `maskedCard`: `string`; `name`: `string`; \}[]; \}\> *** ### getBalance() ```ts getBalance(): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:602](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L602) Retrieve available balances across all active currencies. Useful for dashboards, pre-disbursement checks, and wallet health monitoring. Returns per-currency balance entries with raw provider data for advanced use. #### Returns `Promise`\<`BalanceResult`\> `{ balances: [...] }` with per-currency entries. #### Throws `PesaUnsupportedError` — if the provider does not expose balance data. #### Since 0.2.0 #### Overrides ```ts BasePaymentProvider.getBalance ``` *** ### getNameLookup() ```ts getNameLookup(phoneOrAccount): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:623](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L623) Resolve the account holder name for a phone or account number. Useful for verifying recipient identity before disbursing. #### Parameters | Parameter | Type | | ------ | ------ | | `phoneOrAccount` | `string` | #### Returns `Promise`\<`NameLookupResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support name lookup. #### Overrides ```ts BasePaymentProvider.getNameLookup ``` *** ### getPaymentStatus() ```ts getPaymentStatus(orderId): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:353](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L353) Poll or fetch the current payment status for an order. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<`PaymentStatus`\> #### Overrides ```ts BasePaymentProvider.getPaymentStatus ``` *** ### handleWebhook() ```ts handleWebhook(rawBody, headers): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:485](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L485) Parse + verify an incoming webhook. The provider must: 1. Verify its own cryptographic signature (HMAC, checksum, etc.) 2. Parse the raw body into structured data 3. Return a normalized [PaymentEvent](/docs/api/pesa/interfaces/PaymentEvent) The SDK handles UUID assignment, event persistence, plugin hooks, and user-registered handler emission after this method returns. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)\> #### Overrides ```ts BasePaymentProvider.handleWebhook ``` *** ### listOrders() ```ts listOrders(params): Promise; ``` Defined in: [providers/selcom/src/selcom.ts:572](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L572) List payment orders for a date range. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | `ListOrdersParams` | #### Returns `Promise`\<`ListOrdersResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support listing orders. #### Overrides ```ts BasePaymentProvider.listOrders ``` *** ### lookupUtility() ```ts lookupUtility(utilitycode, utilityref): Promise<{ data: unknown[]; message: string; reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:743](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L743) Look up a utility account before payment. Returns the account holder name and (for some utilities) amount due. #### Parameters | Parameter | Type | | ------ | ------ | | `utilitycode` | `string` | | `utilityref` | `string` | #### Returns `Promise`\<\{ `data`: `unknown`[]; `message`: `string`; `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### payUtility() ```ts payUtility(params): Promise<{ message: string; reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:705](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L705) Pay a utility bill (electricity, water, TV, airtime, etc.). #### Parameters | Parameter | Type | | ------ | ------ | | `params` | \{ `amount`: `number`; `msisdn?`: `string`; `utilitycode`: `string`; `utilityref`: `string`; \} | | `params.amount` | `number` | | `params.msisdn?` | `string` | | `params.utilitycode` | `string` | | `params.utilityref` | `string` | #### Returns `Promise`\<\{ `message`: `string`; `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### previewDisburse()? ```ts optional previewDisburse(_payload): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:139 Preview / dry-run a disbursement before committing. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | `DisbursePayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Inherited from ```ts BasePaymentProvider.previewDisburse ``` *** ### previewOrder()? ```ts optional previewOrder(_payload): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:133 Preview / dry-run a payment before committing. Returns expected fees and validity without charging the customer. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | `CreateOrderPayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Inherited from ```ts BasePaymentProvider.previewOrder ``` *** ### queryUtilityStatus() ```ts queryUtilityStatus(transid): Promise<{ data: unknown[]; message: string; reference: string; status: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:772](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L772) Query the status of a utility payment. #### Parameters | Parameter | Type | | ------ | ------ | | `transid` | `string` | #### Returns `Promise`\<\{ `data`: `unknown`[]; `message`: `string`; `reference`: `string`; `status`: `string`; \}\> *** ### refund()? ```ts optional refund(_orderId, _amount?): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:94 Refund a completed payment. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | | `_amount?` | `number` | #### Returns `Promise`\<`RefundResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support refunds. #### Inherited from ```ts BasePaymentProvider.refund ``` *** ### selcomPesaCashin() ```ts selcomPesaCashin( utilityref, amount, msisdn?): Promise<{ message: string; reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:799](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L799) Send funds to a Selcom Pesa account. #### Parameters | Parameter | Type | Description | | ------ | ------ | ------ | | `utilityref` | `string` | — Selcom Pesa account number or mobile number. | | `amount` | `number` | — amount in TZS. | | `msisdn?` | `string` | — sender mobile number (optional). | #### Returns `Promise`\<\{ `message`: `string`; `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### selcomPesaNameLookup() ```ts selcomPesaNameLookup(utilityref): Promise<{ message: string; name?: string; reference: string; status: string; transid: string; }>; ``` Defined in: [providers/selcom/src/selcom.ts:833](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L833) Look up a Selcom Pesa account holder name. #### Parameters | Parameter | Type | | ------ | ------ | | `utilityref` | `string` | #### Returns `Promise`\<\{ `message`: `string`; `name?`: `string`; `reference`: `string`; `status`: `string`; `transid`: `string`; \}\> *** ### validateCredentials() ```ts validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [providers/selcom/src/selcom.ts:644](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L644) Validate that a provider config works (health check). Useful for startup checks or `/health` endpoints. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> `{ valid: true }` if credentials are correct. #### Throws `PesaUnsupportedError` — if the provider does not support validation. #### Overrides ```ts BasePaymentProvider.validateCredentials ``` --- # @borapesa/selcom ## Classes | Class | Description | | ------ | ------ | | [SelcomPaymentProvider](classes/SelcomPaymentProvider) | - | ## Interfaces | Interface | Description | | ------ | ------ | | [SelcomConfig](interfaces/SelcomConfig) | - | --- # Interface: SelcomConfig Defined in: [providers/selcom/src/selcom.ts:30](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L30) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `apiKey` | `string` | API key from Selcom. | [providers/selcom/src/selcom.ts:34](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L34) | | `apiSecret` | `string` | API secret for HMAC signing. | [providers/selcom/src/selcom.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L36) | | `baseUrl?` | `string` | Base URL. Defaults to https://apigw.selcommobile.com. | [providers/selcom/src/selcom.ts:32](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L32) | | `cancelUrl?` | `string` | Cancel URL for checkout orders. The customer is sent here if they abandon the payment. Base64-encoded per Selcom spec. | [providers/selcom/src/selcom.ts:65](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L65) | | `pin` | `string` | Float account PIN — required for disbursement and balance queries. | [providers/selcom/src/selcom.ts:40](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L40) | | `redirectUrl?` | `string` | Default redirect URL for checkout orders. The customer is sent here after completing payment. Overridable per-payment via CreateOrderPayload.redirectUrl. | [providers/selcom/src/selcom.ts:60](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L60) | | `senderAccount?` | `string` | Source account number for Qwiksend bank transfers. Defaults to vendor if not set. | [providers/selcom/src/selcom.ts:45](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L45) | | `senderName?` | `string` | Account holder display name for bank transfers. Defaults to vendor if not set. | [providers/selcom/src/selcom.ts:50](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L50) | | `senderPhone?` | `string` | Sender mobile number for bank transfers. | [providers/selcom/src/selcom.ts:54](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L54) | | `vendor` | `string` | Float account / vendor identifier. | [providers/selcom/src/selcom.ts:38](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L38) | | `webhookUrl?` | `string` | Webhook callback URL for payment status notifications. Selcom POSTs the payment result here. Typically your pesa.mountWebhook endpoint. Base64-encoded per Selcom spec. | [providers/selcom/src/selcom.ts:71](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/selcom/src/selcom.ts#L71) | --- # Class: SnippePaymentProvider Defined in: [providers/snippe/src/snippe.ts:123](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L123) ## Extends - `BasePaymentProvider` ## Constructors ### Constructor ```ts new SnippePaymentProvider(config): SnippePaymentProvider; ``` Defined in: [providers/snippe/src/snippe.ts:128](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L128) #### Parameters | Parameter | Type | | ------ | ------ | | `config` | [`SnippeConfig`](../interfaces/SnippeConfig) | #### Returns `SnippePaymentProvider` #### Overrides ```ts BasePaymentProvider.constructor ``` ## Properties | Property | Modifier | Type | Default value | Description | Overrides | Defined in | | ------ | ------ | ------ | ------ | ------ | ------ | ------ | | `name` | `readonly` | `ProviderName` | `'snippe'` | Unique provider identifier. | `BasePaymentProvider.name` | [providers/snippe/src/snippe.ts:124](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L124) | ## Methods ### cancelCheckoutSession() ```ts cancelCheckoutSession(reference): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:660](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L660) Cancel a pending or active checkout session. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<`SnippeCheckoutSession`\> *** ### cancelOrder()? ```ts optional cancelOrder(_orderId): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:100 Cancel a pending or in-progress order. #### Parameters | Parameter | Type | | ------ | ------ | | `_orderId` | `string` | #### Returns `Promise`\<`CancelOrderResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support cancellation. #### Inherited from ```ts BasePaymentProvider.cancelOrder ``` *** ### createCheckoutSession() ```ts createCheckoutSession(params): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:610](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L610) Create a hosted checkout session. Returns a `checkoutUrl` for embedding and a `paymentLinkUrl` for sharing via SMS / WhatsApp. The session expires after `expiresIn` seconds (default 3600). #### Parameters | Parameter | Type | | ------ | ------ | | `params` | \{ `amount`: `number`; `description?`: `string`; `expiresIn?`: `number`; `metadata?`: `Record`\<`string`, `unknown`\>; `redirectUrl?`: `string`; \} | | `params.amount` | `number` | | `params.description?` | `string` | | `params.expiresIn?` | `number` | | `params.metadata?` | `Record`\<`string`, `unknown`\> | | `params.redirectUrl?` | `string` | #### Returns `Promise`\<`SnippeCheckoutSession`\> *** ### createOrder() ```ts createOrder(payload): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:276](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L276) Initiate a checkout / USSD push / redirect. The SDK calls `validateCreateOrderPayload()` before this, so you can assume `amount > 0`, `reference` is non-empty, and `customer.phone` is in MSISDN format. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `CreateOrderPayload` | #### Returns `Promise`\<`OrderResult`\> #### Overrides ```ts BasePaymentProvider.createOrder ``` *** ### disburse() ```ts disburse(payload): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:405](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L405) B2C / wallet-out disbursement. The SDK calls `validateDisbursePayload()` before this. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`DisburseResult`\> #### Overrides ```ts BasePaymentProvider.disburse ``` *** ### getBalance() ```ts getBalance(): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:447](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L447) Retrieve available balances across all active currencies. Useful for dashboards, pre-disbursement checks, and wallet health monitoring. Returns per-currency balance entries with raw provider data for advanced use. #### Returns `Promise`\<`BalanceResult`\> `{ balances: [...] }` with per-currency entries. #### Throws `PesaUnsupportedError` — if the provider does not expose balance data. #### Since 0.2.0 #### Overrides ```ts BasePaymentProvider.getBalance ``` *** ### getCheckoutSession() ```ts getCheckoutSession(reference): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:636](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L636) Fetch a checkout session by reference. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<`SnippeCheckoutSession`\> *** ### getNameLookup() ```ts getNameLookup(phoneOrAccount): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:538](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L538) Resolve the account holder name for a phone or account number. Useful for verifying recipient identity before disbursing. #### Parameters | Parameter | Type | | ------ | ------ | | `phoneOrAccount` | `string` | #### Returns `Promise`\<`NameLookupResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support name lookup. #### Overrides ```ts BasePaymentProvider.getNameLookup ``` *** ### getPaymentStatus() ```ts getPaymentStatus(orderId): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:321](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L321) Poll or fetch the current payment status for an order. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<`PaymentStatus`\> #### Overrides ```ts BasePaymentProvider.getPaymentStatus ``` *** ### handleWebhook() ```ts handleWebhook(rawBody, headers): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:334](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L334) Parse + verify an incoming webhook. The provider must: 1. Verify its own cryptographic signature (HMAC, checksum, etc.) 2. Parse the raw body into structured data 3. Return a normalized [PaymentEvent](/docs/api/pesa/interfaces/PaymentEvent) The SDK handles UUID assignment, event persistence, plugin hooks, and user-registered handler emission after this method returns. #### Parameters | Parameter | Type | | ------ | ------ | | `rawBody` | `string` \| `Buffer`\<`ArrayBufferLike`\> | | `headers` | `Record`\<`string`, `string`\> | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)\> #### Overrides ```ts BasePaymentProvider.handleWebhook ``` *** ### listCheckoutSessions() ```ts listCheckoutSessions(params?): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:644](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L644) List checkout sessions (paginated). #### Parameters | Parameter | Type | | ------ | ------ | | `params?` | \{ `limit?`: `number`; `offset?`: `number`; `status?`: `string`; \} | | `params.limit?` | `number` | | `params.offset?` | `number` | | `params.status?` | `string` | #### Returns `Promise`\<`SnippeCheckoutSession`[]\> *** ### listOrders() ```ts listOrders(params): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:457](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L457) List payment orders for a date range. #### Parameters | Parameter | Type | | ------ | ------ | | `params` | `ListOrdersParams` & \{ `paymentType?`: `string`; `q?`: `string`; `status?`: `string`; \} | #### Returns `Promise`\<`ListOrdersResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support listing orders. #### Overrides ```ts BasePaymentProvider.listOrders ``` *** ### previewDisburse() ```ts previewDisburse(payload): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:565](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L565) Preview / dry-run a disbursement before committing. #### Parameters | Parameter | Type | | ------ | ------ | | `payload` | `DisbursePayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Overrides ```ts BasePaymentProvider.previewDisburse ``` *** ### previewOrder()? ```ts optional previewOrder(_payload): Promise; ``` Defined in: packages/pesa/dist/providers/base.d.ts:133 Preview / dry-run a payment before committing. Returns expected fees and validity without charging the customer. #### Parameters | Parameter | Type | | ------ | ------ | | `_payload` | `CreateOrderPayload` | #### Returns `Promise`\<`PreviewResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support preview. #### Inherited from ```ts BasePaymentProvider.previewOrder ``` *** ### refund() ```ts refund(orderId, _amount?): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:579](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L579) Refund a completed payment. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | | `_amount?` | `number` | #### Returns `Promise`\<`RefundResult`\> #### Throws `PesaUnsupportedError` — if the provider does not support refunds. #### Overrides ```ts BasePaymentProvider.refund ``` *** ### retriggerPush() ```ts retriggerPush(reference): Promise; ``` Defined in: [providers/snippe/src/snippe.ts:521](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L521) Re-send the USSD push prompt for a pending mobile payment. Returns the updated payment object. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<`OrderResult`\> *** ### validateCredentials() ```ts validateCredentials(): Promise<{ message?: string; valid: boolean; }>; ``` Defined in: [providers/snippe/src/snippe.ts:503](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L503) Validate that a provider config works (health check). Useful for startup checks or `/health` endpoints. #### Returns `Promise`\<\{ `message?`: `string`; `valid`: `boolean`; \}\> `{ valid: true }` if credentials are correct. #### Throws `PesaUnsupportedError` — if the provider does not support validation. #### Overrides ```ts BasePaymentProvider.validateCredentials ``` --- # @borapesa/snippe ## Classes | Class | Description | | ------ | ------ | | [SnippePaymentProvider](classes/SnippePaymentProvider) | - | ## Interfaces | Interface | Description | | ------ | ------ | | [SnippeConfig](interfaces/SnippeConfig) | - | --- # Interface: SnippeConfig Defined in: [providers/snippe/src/snippe.ts:36](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L36) ## Properties | Property | Type | Description | Defined in | | ------ | ------ | ------ | ------ | | `apiKey` | `string` | Snippe API key (`snp_...`). | [providers/snippe/src/snippe.ts:38](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L38) | | `baseUrl?` | `string` | Base URL override. Defaults to https://api.snippe.sh. | [providers/snippe/src/snippe.ts:42](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L42) | | `cancelUrl?` | `string` | Cancel URL for card payments. The customer is sent here if they abandon the checkout. | [providers/snippe/src/snippe.ts:58](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L58) | | `redirectUrl?` | `string` | Default redirect URL for card payments. The customer is sent here after completing payment. Overridable per-payment via CreateOrderPayload.redirectUrl. | [providers/snippe/src/snippe.ts:53](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L53) | | `timeoutMs?` | `number` | Request timeout in milliseconds (default: 30_000). | [providers/snippe/src/snippe.ts:60](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L60) | | `webhookSecret` | `string` | HMAC-SHA256 signing key for webhook verification. | [providers/snippe/src/snippe.ts:40](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L40) | | `webhookUrl?` | `string` | Default webhook URL applied to createOrder / disburse when the caller doesn't provide one. Provider callbacks POST here. | [providers/snippe/src/snippe.ts:47](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/providers/snippe/src/snippe.ts#L47) | --- # Class: SQLiteAdapter Defined in: [adapters/sqlite/src/index.ts:19](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L19) SQLite event store adapter powered by better-sqlite3. The database file is created at the given path if it doesn't exist. ```ts import { createPesa } from '@borapesa/pesa'; import { SQLiteAdapter } from '@borapesa/sqlite'; const pesa = createPesa({ provider: new SelcomPaymentProvider({...}), db: new SQLiteAdapter('./pesa.db'), }); ``` ## Implements - `PesaDatabaseAdapter` ## Constructors ### Constructor ```ts new SQLiteAdapter(dbPath?): SQLiteAdapter; ``` Defined in: [adapters/sqlite/src/index.ts:23](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L23) #### Parameters | Parameter | Type | Default value | | ------ | ------ | ------ | | `dbPath` | `string` | `'./pesa.db'` | #### Returns `SQLiteAdapter` ## Methods ### getEvent() ```ts getEvent(id): Promise; ``` Defined in: [adapters/sqlite/src/index.ts:72](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L72) Retrieve a single event by its UUID. #### Parameters | Parameter | Type | | ------ | ------ | | `id` | `string` | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent) \| `null`\> #### Implementation of ```ts PesaDatabaseAdapter.getEvent ``` *** ### getEventsByOrderId() ```ts getEventsByOrderId(orderId): Promise; ``` Defined in: [adapters/sqlite/src/index.ts:88](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L88) Retrieve all events for a given provider order ID. #### Parameters | Parameter | Type | | ------ | ------ | | `orderId` | `string` | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)[]\> #### Implementation of ```ts PesaDatabaseAdapter.getEventsByOrderId ``` *** ### getEventsByReference() ```ts getEventsByReference(reference): Promise; ``` Defined in: [adapters/sqlite/src/index.ts:80](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L80) Retrieve all events for a given merchant reference. #### Parameters | Parameter | Type | | ------ | ------ | | `reference` | `string` | #### Returns `Promise`\<[`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent)[]\> #### Implementation of ```ts PesaDatabaseAdapter.getEventsByReference ``` *** ### saveEvent() ```ts saveEvent(event): Promise; ``` Defined in: [adapters/sqlite/src/index.ts:51](https://github.com/borapesa/pesa/blob/b8acb48dd4efd184ada1ab34d92be1f54617b433/adapters/sqlite/src/index.ts#L51) Persist a verified PaymentEvent. #### Parameters | Parameter | Type | | ------ | ------ | | `event` | [`PaymentEvent`](/docs/api/pesa/interfaces/PaymentEvent) | #### Returns `Promise`\<`void`\> #### Implementation of ```ts PesaDatabaseAdapter.saveEvent ``` --- # @borapesa/sqlite ## Classes | Class | Description | | ------ | ------ | | [SQLiteAdapter](classes/SQLiteAdapter) | SQLite event store adapter powered by better-sqlite3. |