Nepal Payment Gateway SDK (eSewa & Khalti)
A developer-first, typesafe, server-side TypeScript SDK for integrating Nepal’s leading digital payment gateways: eSewa (ePay v2) and Khalti (ePayment v2). Built for modern backend runtimes with strict integer paisa arithmetic, mandatory server-to-server (S2S) verification, and zero client-side credential leaks.
Quick Installation
Section titled “Quick Installation”Install via your preferred package manager (Node 18+ required):
npm install @bivekkk/nepay# Alternative package managerspnpm add @bivekkk/nepayyarn add @bivekkk/nepaybun add @bivekkk/nepayFirst Payment in 60 Seconds
Section titled “First Payment in 60 Seconds”The SDK provides two core functions: initiatePayment() and verifyPayment(). Passing method: "esewa" or method: "khalti" automatically discriminates input parameters and return types with full TypeScript intellisense.
Step 1: Initiate Payment
Section titled “Step 1: Initiate Payment”import { initiatePayment } from "@bivekkk/nepay";
// 1. Initiate eSewa paymentconst checkout = await initiatePayment({ method: "esewa", config: { productCode: process.env.ESEWA_PRODUCT_CODE || "EPAYTEST", secretKey: process.env.ESEWA_SECRET_KEY || "8gBm/:&EnhH.1/q", successUrl: "https://yourdomain.com/api/payment/callback/esewa", failureUrl: "https://yourdomain.com/api/payment/callback/esewa", env: "sandbox", }, order: { orderId: "INV-2024-001", amountPaisa: 10000, // NPR 100.00 (float-safe integer paisa) },});
// Returns form target URL and cryptographic HMAC-SHA256 signature fields:// { url: "https://rc-epay.esewa.com.np/api/epay/main/v2/form", fields: { ... } }Line-by-Line Breakdown
Section titled “Line-by-Line Breakdown”method: "esewa": Discriminates the input schema using Zod, ensuring only eSewa-specific options are accepted and returning{ url, fields }.config.productCode: Your merchant identifier ("EPAYTEST"in UAT sandbox).config.secretKey: The HMAC secret key used for signing payload fields. Keep this server-side only.order.orderId: Unique transaction ID in your database (transaction_uuidin eSewa).order.amountPaisa: Always integer paisa.10000paisa represents exactlyNPR 100.00.
Step 2: Mandatory Server-to-Server Verification
Section titled “Step 2: Mandatory Server-to-Server Verification”When the customer finishes payment, eSewa redirects back to your successUrl with a base64 encoded payload. verifyPayment() validates the signature and queries eSewa’s status endpoint to confirm receipt before marking the order complete.
import { verifyPayment } from "@bivekkk/nepay";
// 2. Verify eSewa callback on your serverconst result = await verifyPayment({ method: "esewa", config: { productCode: process.env.ESEWA_PRODUCT_CODE || "EPAYTEST", secretKey: process.env.ESEWA_SECRET_KEY || "8gBm/:&EnhH.1/q", env: "sandbox", }, data: req.query.data as string, // Base64 payload from eSewa redirect expectedOrderId: "INV-2024-001", expectedAmountPaisa: 10000,});
if (result.status === "completed") { // Safe to mark paid in your database console.log("Payment confirmed! Gateway Ref ID:", result.traceId);} else { console.error("Verification failed:", result.status);}Why S2S Verification is Mandatory
Section titled “Why S2S Verification is Mandatory”Browser redirects can be intercepted, spoofed, or replayed by malicious users. The SDK guarantees:
- Timing-Safe HMAC Check: Validates the cryptographic digest with
crypto.timingSafeEqualagainst the received raw string. - Gateway Lookup: Queries the gateway’s server endpoint to verify the transaction status and amount.
- Exact Amount Match: Checks that the paid amount matches
expectedAmountPaisato the exact paisa.
Gateway Support Matrix
Section titled “Gateway Support Matrix”| Gateway | Protocol / Version | Initiate Mechanism | Verification Mechanism | Environment |
|---|---|---|---|---|
| eSewa | ePay v2 | HTML Form POST + HMAC-SHA256 | S2S Status API + Base64 Callback | Sandbox (UAT) & Production |
| Khalti | ePayment v2 (KPG-2) | REST JSON (/epayment/initiate/) |
S2S Lookup API (/epayment/lookup/) |
Sandbox & Production |
| FonePay | Dynamic QR / Web | Direct Merchant API | Webhook + S2S Query | Phase 2 Roadmap |
Core Principles
Section titled “Core Principles”- Float-Safe Integer Paisa: All amounts in the API are integer paisa (
1 NPR = 100 Paisa). Eliminates JavaScript float drift (0.1 + 0.2 !== 0.3). - Server-Only Security: Secret keys never leak to frontend bundles. All cryptographic operations run inside Node.js or server runtimes.
- Resilient Formatting: Automatic parsing of eSewa callback quirks (e.g. comma strings
"1,000.0"), GET vs POST callback normalization, and Khalti HTTP 400 Expired body handling. - Dual ESM & CommonJS: Ships with dual entrypoints and TypeScript definition files for complete compatibility with Next.js, Remix, Express, NestJS, and Fastify.
Next Steps
Section titled “Next Steps”Step-by-step tutorial covering both eSewa and Khalti end-to-end lifecycles.
Form POST auto-submission, signature generation, and GET/POST callback resolution.
REST initiate, pidx lookup verification, sandbox credentials, and expired state handling.
Production Express server with checkout endpoints, callback routes, and database patterns.
Modern Next.js 14/15 implementation using Server Actions and Route Handlers.
Complete method signatures, parameter tables, and TypeScript types.