npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

esewa-api-wrapper

v1.0.0

Published

A secure and developer-friendly Node.js wrapper for seamless integration with the eSewa Payment Gateway.

Readme

💚 esewa-api-wrapper

A secure and developer-friendly Node.js wrapper for seamless integration with the eSewa Payment Gateway.

npm version License: MIT TypeScript Node.js CI

Installation · Quick Start · API Reference · Examples · Security


✨ Features

  • 🔐 HMAC-SHA256 Signed Requests — Automatic signature generation & verification
  • 🛡️ Tamper-Proof Responses — Timing-safe signature verification prevents fraud
  • 🏗️ TypeScript First — Full type definitions with comprehensive JSDoc
  • 🌐 Dual Environment — Seamless switching between sandbox and production
  • 📦 ESM + CommonJS — Works everywhere — import or require
  • 🔄 Auto Retry — Exponential backoff for transient network failures
  • 🪵 Debug Logging — Optional logs with automatic sensitive data masking
  • Zero Dependencies — Uses only Node.js built-in modules
  • 🌳 Tree-Shakable — Import only what you need

📦 Installation

npm install esewa-api-wrapper
yarn add esewa-api-wrapper
pnpm add esewa-api-wrapper

🔧 Environment Setup

Create a .env file in your project root:

cp node_modules/esewa-api-wrapper/.env.example .env
# .env
ESEWA_MERCHANT_ID=EPAYTEST
ESEWA_SECRET_KEY=8gBm/:&EnhH.1/q
ESEWA_ENVIRONMENT=sandbox
ESEWA_SUCCESS_URL=http://localhost:3000/payment/success
ESEWA_FAILURE_URL=http://localhost:3000/payment/failure

⚠️ Never commit .env to version control. Add it to .gitignore.

Sandbox Test Credentials

| Field | Value | |-------|-------| | Merchant ID | EPAYTEST | | Secret Key | 8gBm/:&EnhH.1/q | | eSewa ID | 9806800001 to 9806800005 | | Password | Nepal@123 | | MPIN | 1122 | | OTP Token | 123456 |


🚀 Quick Start

import { EsewaClient } from 'esewa-api-wrapper';

// Initialize the client
const esewa = new EsewaClient({
  merchantId: 'EPAYTEST',
  secretKey: process.env.ESEWA_SECRET_KEY!,
  environment: 'sandbox',
  successUrl: 'https://yourdomain.com/payment/success',
  failureUrl: 'https://yourdomain.com/payment/failure',
});

// 1. Create a payment
const payment = esewa.createPayment({
  amount: 1000,
  taxAmount: 0,
  serviceCharge: 0,
  deliveryCharge: 0,
  transactionUuid: esewa.generateTransactionUuid(),
  productCode: 'EPAYTEST',
});

console.log(payment.url);      // eSewa payment form URL
console.log(payment.formData); // Signed form data to POST

// 2. Verify a payment (after success callback)
const status = await esewa.verifyPayment({
  transactionUuid: 'your-transaction-uuid',
  totalAmount: 1000,
  productCode: 'EPAYTEST',
});

if (status.status === 'COMPLETE') {
  console.log('Payment confirmed!', status.ref_id);
}

📖 API Reference

new EsewaClient(config)

Creates a new eSewa client instance.

interface EsewaConfig {
  merchantId: string;           // Your eSewa merchant ID
  secretKey: string;            // HMAC secret key (from eSewa)
  environment: 'sandbox' | 'production';
  successUrl: string;           // Redirect URL on success
  failureUrl: string;           // Redirect URL on failure
  enableLogging?: boolean;      // Debug logging (default: false)
  maxRetries?: number;          // Network retry attempts (default: 3)
  retryDelay?: number;          // Base retry delay ms (default: 1000)
  timeout?: number;             // Request timeout ms (default: 30000)
}

esewa.createPayment(options): PaymentInitiationResult

Generates a signed payment URL and form data for redirecting users to eSewa.

const { url, formData } = esewa.createPayment({
  amount: 1000,           // Base price
  taxAmount: 130,         // Tax (optional, default: 0)
  serviceCharge: 0,       // Service charge (optional, default: 0)
  deliveryCharge: 0,      // Delivery charge (optional, default: 0)
  transactionUuid: esewa.generateTransactionUuid(),
  productCode: 'EPAYTEST',
});

// Redirect user via POST to `url` with `formData` as body

Returns:

interface PaymentInitiationResult {
  url: string;              // eSewa payment endpoint URL
  formData: PaymentFormData; // All signed form fields
}

esewa.generatePaymentForm(options): string

Returns a complete auto-submitting HTML page. Ideal for server-rendered apps.

// Express.js
app.post('/pay', (req, res) => {
  const html = esewa.generatePaymentForm({
    amount: 1000,
    transactionUuid: esewa.generateTransactionUuid(),
    productCode: 'EPAYTEST',
  });
  res.setHeader('Content-Type', 'text/html');
  res.send(html);
});

esewa.verifyPayment(options): Promise<PaymentVerificationResponse>

Server-to-server verification via eSewa's status check API.

const result = await esewa.verifyPayment({
  transactionUuid: 'your-transaction-uuid',
  totalAmount: 1000,
  productCode: 'EPAYTEST',
});

// result.status: 'COMPLETE' | 'PENDING' | 'FULL_REFUND' | 'PARTIAL_REFUND' |
//                'AMBIGUOUS' | 'NOT_FOUND' | 'CANCELED'
// result.ref_id:  eSewa reference ID (e.g., '0001TS9')

esewa.decodeResponse(encodedData): EsewaPaymentResponse

Decodes and signature-verifies the Base64-encoded response from eSewa's success redirect.

// Express.js success callback
app.get('/payment/success', (req, res) => {
  try {
    const response = esewa.decodeResponse(req.query.data as string);
    // response.status === 'COMPLETE'
    // response.transaction_code === '000AWEO'
    // response.total_amount === 1000
  } catch (error) {
    if (error instanceof SignatureError) {
      // ⚠️ Possible tampering — DO NOT process this payment
    }
  }
});

esewa.verifyWebhookSignature(payload, signature?): WebhookVerificationResult

Verifies incoming webhook notification signatures.

app.post('/webhook/esewa', (req, res) => {
  const result = esewa.verifyWebhookSignature(
    req.body,
    req.headers['x-esewa-signature'] as string
  );

  if (result.isValid) {
    // Process result.payload
    res.json({ received: true });
  } else {
    res.status(403).json({ error: result.error });
  }
});

esewa.initiateRefund(options): Promise<RefundResponse>

Checks refund eligibility and current transaction status.

const refund = await esewa.initiateRefund({
  transactionUuid: 'your-transaction-uuid',
  amount: 500,
  productCode: 'EPAYTEST',
  reason: 'Customer requested refund',
});

Utility Methods

| Method | Description | |--------|-------------| | esewa.generateTransactionUuid() | Generates a unique YYMMDD-xxxxxxxxxxxx transaction ID | | esewa.calculateTotalAmount(request) | Sums amount + tax + service + delivery charges | | esewa.signPayload(payload) | Signs any { key: value } object with HMAC-SHA256 | | esewa.verifySignature(payload, sig, fields) | Timing-safe signature verification | | esewa.getEnvironmentBaseUrl() | Returns { payment, status } URLs for current env | | esewa.getEnvironment() | Returns 'sandbox' or 'production' | | esewa.getMerchantId() | Returns the configured merchant ID |


Standalone Exports (Tree-Shakable)

For serverless or size-sensitive environments, import only what you need:

import {
  generatePaymentSignature,
  verifySignature,
  generateTransactionUuid,
  calculateTotalAmount,
  getPaymentUrl,
} from 'esewa-api-wrapper';

💡 Examples

Express.js Integration

See the complete example: examples/express-example.ts

import express from 'express';
import { EsewaClient, SignatureError } from 'esewa-api-wrapper';

const app = express();
const esewa = new EsewaClient({ /* config */ });

// Initiate payment
app.post('/pay', (req, res) => {
  const html = esewa.generatePaymentForm({
    amount: parseFloat(req.body.amount),
    transactionUuid: esewa.generateTransactionUuid(),
    productCode: 'EPAYTEST',
  });
  res.send(html);
});

// Verify payment
app.get('/payment/success', async (req, res) => {
  const response = esewa.decodeResponse(req.query.data as string);
  const status = await esewa.verifyPayment({
    transactionUuid: response.transaction_uuid,
    totalAmount: response.total_amount,
    productCode: response.product_code,
  });

  if (status.status === 'COMPLETE') {
    res.send('Payment successful!');
  }
});

Next.js Integration

See the complete example: examples/nextjs-example.ts

// app/api/payment/initiate/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { esewa } from '@/lib/esewa';

export async function POST(request: NextRequest) {
  const { amount } = await request.json();

  const payment = esewa.createPayment({
    amount,
    transactionUuid: esewa.generateTransactionUuid(),
    productCode: process.env.ESEWA_PRODUCT_CODE!,
  });

  return NextResponse.json({
    paymentUrl: payment.url,
    formData: payment.formData,
  });
}

🔐 Security

Best Practices

  1. Never expose secretKey client-side — Keep it in environment variables on the server only.

  2. Always verify payments server-to-server — After receiving a success callback, call verifyPayment() to confirm with eSewa directly.

  3. Validate response signatures — Use decodeResponse() which automatically verifies HMAC-SHA256 signatures before returning data.

  4. Use HTTPS in production — The client enforces HTTPS for success/failure URLs in production mode.

  5. Generate unique transaction UUIDs — Use generateTransactionUuid() to prevent replay attacks.

  6. Verify webhook signatures — Always call verifyWebhookSignature() before processing webhook data.

How Signatures Work

┌─────────────────────────────────────────────────────┐
│                 Payment Request                      │
│                                                      │
│  Message: "total_amount=110,transaction_uuid=241028, │
│            product_code=EPAYTEST"                    │
│                                                      │
│  Secret Key: "8gBm/:&EnhH.1/q"                     │
│                                                      │
│  HMAC-SHA256 → Base64                                │
│                                                      │
│  Signature: "i94zsd3oXF6ZsSr/kGqT4sSzYQzjj1W/..."  │
└─────────────────────────────────────────────────────┘

Security Features

| Feature | Implementation | |---------|---------------| | Request Signing | HMAC-SHA256 with Base64 encoding | | Response Verification | Timing-safe signature comparison | | Anti-Tampering | Signed field verification | | Replay Prevention | Unique transaction UUIDs | | Data Protection | Sensitive data masking in logs | | HTTPS Enforcement | Required in production mode | | Input Sanitization | All inputs validated & sanitized |


🏗️ Transaction Flow

┌──────────┐    1. createPayment()     ┌──────────┐
│          │ ──────────────────────────▶│          │
│  Your    │    2. Redirect (POST)      │  eSewa   │
│  Server  │ ──────────────────────────▶│  ePay    │
│          │                            │          │
│          │    3. Success redirect      │          │
│          │ ◀──────────────────────────│          │
│          │    4. decodeResponse()      │          │
│          │                            │          │
│          │    5. verifyPayment()       │          │
│          │ ──────────────────────────▶│          │
│          │    6. Status response       │          │
│          │ ◀──────────────────────────│          │
└──────────┘                            └──────────┘

🧪 Error Handling

The package provides specialized error classes for precise error handling:

import {
  EsewaError,        // Base error class
  ValidationError,   // Invalid input/config
  SignatureError,     // Signature mismatch (possible tampering)
  NetworkError,       // API request failures
  ConfigurationError, // Client misconfiguration
} from 'esewa-api-wrapper';

try {
  await esewa.verifyPayment({ /* ... */ });
} catch (error) {
  if (error instanceof SignatureError) {
    // ⚠️ Possible tampering detected
  } else if (error instanceof NetworkError) {
    // 🌐 eSewa API unreachable — retry later
  } else if (error instanceof ValidationError) {
    // ❌ Invalid parameters
  }
}

All errors include:

  • code — Machine-readable error code (e.g., SIGNATURE_ERROR)
  • message — Human-readable description
  • details — Additional context (optional)
  • cause — Original error for chain tracing (optional)

📁 Project Structure

esewa-api-wrapper/
├── src/
│   ├── client.ts           # Main EsewaClient class
│   ├── config.ts           # Configuration management
│   ├── errors.ts           # Custom error classes
│   ├── payment.ts          # Payment initiation & form generation
│   ├── verification.ts     # Response decoding & status verification
│   ├── webhook.ts          # Webhook signature verification
│   ├── types/
│   │   └── index.ts        # All TypeScript interfaces & types
│   ├── utils/
│   │   ├── crypto.ts       # HMAC-SHA256 signature utilities
│   │   ├── validator.ts    # Input validation & sanitization
│   │   └── helpers.ts      # URL builders, Base64, HTTP, logging
│   └── index.ts            # Package entry point (barrel exports)
├── tests/                  # Vitest test suites
├── examples/               # Express.js & Next.js examples
├── .github/workflows/      # CI/CD pipeline
├── package.json
├── tsconfig.json
└── README.md

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Build
npm run build

# Lint
npm run lint

# Format
npm run format

📄 License

MIT © Diwas Atreya