
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
i know payment integration seem very hard as when i try to integrate it i felt very overwhelmed and reading those whole docs seem very time consuming so i just made a NPM package to simplify this
npm i esewajs
import { EsewaPaymentGateway } from "esewajs";
await EsewaPaymentGateway(amount,productDeliveryCharge,productServiceCharge,taxAmount,transaction_uuid,
product_code,SECRET,success_url,failure_url,ESEWAPAYMENT_URL,undefined,undefined)
there is 2 undefined first one is for algorithm which is set to sha256 by default as esewa use it and another is encoding which is set to base64 by default || as u can write it explictly too
import { EsewaCheckStatus } from "esewajs";
await EsewaCheckStatus(total_amount,transaction_uuid,product_code,ESEWAPAYMENT_STATUS_CHECK_URL)
1. npm install axios
2. npm i body-parser
3. npm i dotenv
4. npm i express
5. npm i mongoose
6. npm i esewajs
module.js
import { EsewaPaymentGateway,EsewaCheckStatus } from "esewajs";
common.js
const { EsewaPaymentGateway, EsewaCheckStatus } = require('esewajs');
module.js
import { generateUniqueId,base64Decode } from "esewajs";
common.js
const { generateUniqueId,base64Decode } = require('esewajs');

project -Backend folder

import dotenv from "dotenv";
import express from "express";
import bodyParser from "body-parser";
import cors from "cors";
import { EsewaInitiatePayment, paymentStatus } from "./src/esewa.controller.js";
import connectDB from "./src/DB/db.config.js"
// Load environment variables from .env file
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
connectDB();
app.use(cors('http://localhost:5173',credential:true));//replace with your local host
//middle ware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//routes
app.post("/initiate-payment", EsewaInitiatePayment);
app.post("/payment-status", paymentStatus);
//start server
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
DB / db.config.js
import mongoose from "mongoose";
const connectDB = async() => {
try {
await mongoose.connect('mongodb://127.0.0.1:27017/mydatabase').then((res) => {
console.log("MongoDB connected successfully");
});
} catch (error) {
console.error("MongoDB connection error:", error);
}
};
export default connectDB;
model / Transaction.model.js
import mongoose from "mongoose";// Define the Transaction schema
const transactionSchema = new mongoose.Schema(
{product_id: {
type: String,
required: true,
},
amount: {
type: Number,
required: true,
min: 0, // Amount should not be negative
},
status: {
type: String,
required: true,
enum: ["PENDING", "COMPLETE", "FAILED", "REFUNDED"], // Example statuses
default: "PENDING",
},
},
{
timestamps: true, // Adds createdAt and updatedAt fields automatically
}
);
// Create the Transaction model from the schema
export const Transaction = mongoose.model("Transaction", transactionSchema);
esewa.controller.js
import { Transaction } from "./model/Transaction.model.js"; //for saving the ordered data in database
import { EsewaPaymentGateway,EsewaCheckStatus } from "esewajs"; //we install our package hehe
const EsewaInitiatePayment=async(req,res)=>{
const { amount, productId } = req.body; //data coming from frontend
try {
const reqPayment=await EsewaPaymentGateway(
amount,0,0,0,productId,process.env.MERCHANT_ID,process.env.SECRET,process.env.SUCCESS_URL,process.env.FAILURE_URL,process.env.ESEWAPAYMENT_URL,undefined,undefined)
if(!reqPayment){
return res.status(400).json("error sending data")
}
if (reqPayment.status === 200) {
const transaction = new Transaction({
product_id: productId,
amount: amount,
});
await transaction.save();
console.log("transaction passed ")
return res.send({
url: reqPayment.request.res.responseUrl,
});
}
}
catch (error) {
return res.status(400).json("error sending data")
}}
const paymentStatus=async (req, res) => {
const { product_id } = req.body; // Extract data from request body
try {
// Find the transaction by its signature
const transaction = await Transaction.findOne({ product_id });
if (!transaction) {
return res.status(400).json({ message: "Transaction not found" });
}
const paymentStatusCheck=await EsewaCheckStatus(transaction.amount,transaction.product_id,process.env.MERCHANT_ID,process.env.ESEWAPAYMENT_STATUS_CHECK_URL)
if (paymentStatusCheck.status === 200) {
// Update the transaction status
transaction.status = paymentStatusCheck.data.status;
await transaction.save();
res
.status(200)
.json({ message: "Transaction status updated successfully" });
}
} catch (error) {
console.error("Error updating transaction status:", error);
res.status(500).json({ message: "Server error", error: error.message });
}
};
export {EsewaInitiatePayment,paymentStatus}
.env
PORT=3000
MONGO_URI=mongodb://127.0.0.1:27017/mydatabase
MERCHANT_ID=EPAYTEST
SUCCESS_URL=http://localhost:5173/payment-success
FAILURE_URL=http://localhost:5173/payment-failure
ESEWAPAYMENT_URL=https://rc-epay.esewa.com.np/api/epay/main/v2/form
SECRET=8gBm/:&EnhH.1/q
ESEWAPAYMENT_STATUS_CHECK_URL=https://rc.esewa.com.np/api/epay/transaction/status/
Production: https://epay.esewa.com.np/api/epay/main/v2/form
*for testing locally use ESEWAPAYMENT_URL= https://rc-epay.esewa.com.np/api/epay/main/v2/form in .env file *
for production use ESEWAPAYMENT_URL= https://epay.esewa.com.np/api/epay/main/v2/form in .env file *
MERCHANT_ID will be provided by esewa ,you should reach out to them Success_URL is for esewa redirect your browser to your custommade sucesspage and if it fail it will redirect to your failure page
Backend setup complete

install this in your frontend folder terminal
create 3 file
**remember we gave sucess URL in the .env and were passing in the esewajs package ,yes so that esewa will redirect us to the url which is either success or failure payment page
Payment.jsx
import React, { useState } from "react";
import axios from "axios";
import { generateUniqueId } from "esewajs";
const PaymentComponent = () => {
const [amount, setAmount] = useState("");
const handlePayment = async (e) => {
e.preventDefault();
try {
const response = await axios.post(
"http://localhost:3000/initiate-payment", //server payment route
{
amount,
productId: generateUniqueId(),
}
);
window.location.href = response.data.url;
} catch (error) {
console.error("Error initiating payment:", error);
}
};
return (
<div>
<h1>eSewa Payment Integration</h1>
<div className="form-container" onSubmit={handlePayment}>
<form className="styled-form">
<div className="form-group">
<label htmlFor="Amount">Amount:</label>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
required
placeholder="Enter amount"
/>
</div>
<button type="submit" className="submit-button">
Pay with eSewa
</button>
</form>
</div>
</div>
);
};
export default PaymentComponent;
failure.jsx
import React from "react";
import { useNavigate } from "react-router-dom";
const Failure = () => {
const navigate = useNavigate();
return (
<div>
<h1>Payment Failed!</h1>
<p>There was an issue with your payment. Please try again.</p>
<button onClick={() => navigate("/")} className="go-home-button">
Go to Homepage
</button>
</div>
)
};
export default Failure;
Success.jsx
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import {base64Decode} from "esewajs"
import axios from "axios";
const Success = () => {
const [isSuccess, setIsSuccess] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const navigate = useNavigate();
const location = useLocation();
// Create a new URLSearchParams object using the search string from location
const queryParams = new URLSearchParams(location.search);
const token = queryParams.get("data");
// Decode the JWT without verifying the signature
const decoded = base64Decode(token);
const verifyPaymentAndUpdateStatus = async () => {
try {
const response = await axios.post(
"http://localhost:3000/payment-status",
{
product_id: decoded.transaction_uuid,
}
);
if (response.status === 200) {
setIsLoading(false);
setIsSuccess(true);
}
} catch (error) {
setIsLoading(false);
console.error("Error initiating payment:", error);
}
};
useEffect(() => {
verifyPaymentAndUpdateStatus();
}, []);
if (isLoading && !isSuccess) return <>Loading...</>;
if (!isLoading && !isSuccess)
return (
<>
<h1>Oops!..Error occurred on confirming payment</h1>
<h2>We will resolve it soon.</h2>
<button onClick={() => navigate("/")} className="go-home-button">
Go to Homepage
</button>
</>
);
return (
<div>
<h1>Payment Successful!</h1>
<p>Thank you for your payment. Your transaction was successful.</p>
<button onClick={() => navigate("/")} className="go-home-button">
Go to Homepage
</button>
</div>
);
};
export default Success;
the esewa provide addition data to the success URL so we have to decode it will base64 decode fucntion
in the app.jsx
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Failure from "./components/Failure";
import PaymentComponent from "./components/PaymentForm";
import Success from "./components/Success";
function App() {
return (
<Router>
<div className="App">
<Routes>
<Route path="/" element={<PaymentComponent />} />
<Route path="/payment-success" element={<Success />} />
<Route path="/payment-failure" element={<Failure />} />
</Routes>
</div>
</Router>
);
}
export default App;
congrats u made a Esewa payment integration You can read More detail docs if u want Transaction Flow
When user choses eSewa as on-line payment option from partner merchant application, then user is temporarily redirected to eSewa ePay login page.
User will provide valid credentials on login page.
By confirming the transaction, user is accepting the transaction details sent by partner merchants.
After each successful transaction, the user is redirected back to partner merchant's success page. If transaction fails due to any reason (which includes user canceling transaction), the user is informed by appropriate failure message and redirected back to partner merchant's failure page.
For every successful transaction, the merchant account is credited accordingly and notified via email/SMS regarding transaction.
If a response is not received within five minutes, the status check API can be used to confirm the payment.
After receiving a response from the status check API, update the payment status accordingly.
const reqPayment=await EsewaPaymentGateway(amount,productDeliveryCharge,productServiceCharge,taxAmount,productId,process.env.MERCHANT_ID,process.env.SECRET,process.env.SUCCESS_URL,process.env.FAILURE_URL,process.env.ESEWAPAYMENT_URL,algorithm,encoding)
for developement phase use productDeliveryCharge=0, productServiceCharge=0, taxAmount=0
also work without explictly defining it
const reqPayment=await EsewaPaymentGateway(amount,productDeliveryCharge,productServiceCharge,taxAmount,productId,process.env.MERCHANT_ID,process.env.SECRET,process.env.SUCCESS_URL,process.env.FAILURE_URL,process.env.ESEWAPAYMENT_URL,undefined,undefined)
*if u want to use it explictly u can use it like this *
const reqPayment=await EsewaPaymentGateway(amount,productDeliveryCharge,productServiceCharge,taxAmount,productId,process.env.MERCHANT_ID,process.env.SECRET,process.env.SUCCESS_URL,process.env.FAILURE_URL,process.env.ESEWAPAYMENT_URL,"sha256","base64")
* as esewa use sha256 algorithm and base64 for encoding*
the EsewaPaymentGateway function helps the browser to redirect to the esewa payment gateway and then help in transaction flow *the EsewaCheckStatus function is used to check if the payment is done or not by providing the product code to the esewa server *
the generateUniqueId function helps to generate a unique id for the product so that esewa will accept it as product id and amount is send directly *the base64Decode function is use to decode the informatin as if the payment is successful esewa redirect us to the success_url as we have in .env file as we proviude in function too * await EsewaPaymentGateway(amount,productDeliveryCharge,productServiceCharge,taxAmount,transaction_uuid, product_code,SECRET,success_url,failure_url,ESEWAPAYMENT_URL,algorithm,encoding)
we use algorithm and encoding as undefined in the doc because when u left it undefined by default it will take algorithm and encoding of Esewa i.e. hsa256 and base64
FAQs
a normal NPM package to simplify Esewa payment integration
We found that esewajs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.