PayBridgeNP
eSewaDeveloperPayment gatewayNepal

eSewa API Integration in Nepal: A Developer's Guide (2026)

How eSewa's ePay v2 checkout works for developers: the signed form, the success redirect, the status check that confirms payment, testing in the sandbox, the traps that cause NOT_FOUND, and the shorter path through one API.

October 22, 20266 min readPayBridgeNP Team
eSewa API Integration in Nepal: A Developer's Guide (2026)

eSewa is the wallet most Nepali customers already have, so it is usually the first payment method a developer is asked to add. The integration itself is small: a signed form, a redirect back to your site, and one status call. What takes the time is the detail around it. The amount has to be sent back exactly as you first sent it, a transaction ID can never be reused, and the redirect alone proves nothing.

This guide covers eSewa's web checkout (ePay v2) end to end, the way we run it in production.

Last checked: 22 October 2026, against the eSewa integration PayBridgeNP runs for live merchants. Looking for the merchant login or how to register? That is in the eSewa merchant account guide.

How an eSewa ePay payment works

There are three steps, and the third is the one that matters:

  1. Your server signs a form with the amount and a transaction ID you generate, and your page posts that form to eSewa.
  2. The customer pays in eSewa and is sent back to your success_url with a data parameter: base64-encoded JSON describing the payment, signed by eSewa.
  3. Your server confirms the payment with eSewa's status check before you mark the order paid.
Test (sandbox)Live
Payment formhttps://rc-epay.esewa.com.np/api/epay/main/v2/formhttps://epay.esewa.com.np/api/epay/main/v2/form
Status checkhttps://rc-epay.esewa.com.np/api/epay/transaction/status/https://epay.esewa.com.np/api/epay/transaction/status/
Product codeEPAYTESTYour merchant code, from eSewa

Step 1: the signed payment form

The form carries the amounts, your product code, a unique transaction_uuid, your success and failure URLs, and a signature. The fields are:

FieldWhat goes in it
amountThe order amount in rupees, for example 100.00
tax_amount, product_service_charge, product_delivery_chargeUsually 0
total_amountThe sum of the four above. This is the amount the customer pays
transaction_uuidAn ID you generate for this attempt. Never reuse it
product_codeEPAYTEST in sandbox, your merchant code live
success_url, failure_urlWhere eSewa sends the customer back
signed_field_namestotal_amount,transaction_uuid,product_code
signatureSee below

The signature is an HMAC-SHA256 of the signed fields, joined in the order you listed them, using the secret key eSewa gave you, and encoded as base64:

message   = "total_amount=100.00,transaction_uuid=ord-1042-a1,product_code=EPAYTEST"
signature = base64( HMAC_SHA256( secret_key, message ) )

Generate the signature on your server. The secret key must never reach the browser or your mobile app.

Step 2: the success redirect

After payment, eSewa redirects the customer to your success_url with ?data= holding base64-encoded JSON. Decoded, it includes transaction_code (eSewa's own reference for the payment), status, total_amount, transaction_uuid, product_code, and its own signed_field_names and signature.

Verify that signature with your secret key, using the field list eSewa sent. Then treat the result as a hint, not proof: anyone can open your success URL, and a signed message tells you what eSewa said at that moment, not that you should ship goods.

Step 3: confirm with the status check

Call the status endpoint with the same three values you signed:

GET /api/epay/transaction/status/?product_code=EPAYTEST&total_amount=100.00&transaction_uuid=ord-1042-a1

Only a status of COMPLETE means paid. The others you will meet:

StatusWhat it means for the order
COMPLETEPaid. Fulfil the order
PENDINGNot finished yet. Check again later; do not fail the order
NOT_FOUNDeSewa has no payment for these values. Often a wrong amount string or an expired attempt
CANCELEDCancelled or reversed on eSewa's side. Do not fulfil
AMBIGUOUSeSewa could not give a clear answer. Hold the order and check again
FULL_REFUND, PARTIAL_REFUNDAlready refunded by eSewa

A timeout or error from the status check is not a failed payment either. The customer may have paid; ask again before you tell them anything.

The traps that cause most eSewa bugs

The amount string must match exactly. The status check expects total_amount as the same string you sent in the form. If you sent 100.00 and later query 100, eSewa can answer NOT_FOUND for a payment that went through. Store the exact string with the order.

A transaction_uuid is single use, even after a failure. eSewa remembers every ID it has seen. Retrying a failed payment with the same ID does not work: generate a new one for every attempt, and keep the link between attempts and the order on your side.

Amounts are in rupees here. Many systems, PayBridgeNP included, keep money in paisa as whole numbers. Convert once, at the edge, and test an amount with paisa in it.

Refunds are not an API call. eSewa refunds are handled with eSewa, outside this checkout, so plan the support process before your first refund request.

The mobile SDKs are deprecated. eSewa's Android, iOS and Flutter SDKs are marked deprecated in its developer docs. For an app, use the web checkout inside the app, or eSewa's newer Intent flow, which opens the eSewa app directly. eSewa recommends Intent and grants access to it separately, so ask for it when you apply.

Testing in the sandbox

The sandbox is a real eSewa test environment, so you can run the whole loop before you have a live agreement, with the product code EPAYTEST, its test secret key and eSewa's shared test accounts. All of the values, and the mistakes that make test payments fail, are in eSewa test credentials and sandbox. Test the success path, then a cancellation, then a status check with a deliberately wrong amount, so you know what NOT_FOUND looks like before a customer finds it.

The shorter path: one API for eSewa, Khalti and Fonepay

If eSewa is the only method you will ever take, the three steps above are manageable on their own. Most Nepali shops end up wanting Khalti and Fonepay as well, each with its own signing, redirect and confirmation rules.

With PayBridgeNP you connect your own eSewa merchant account once and create one checkout session for any provider:

import { PayBridgeNP } from "@paybridge-np/sdk";

const paybridge = new PayBridgeNP({ apiKey: process.env.PAYBRIDGENP_API_KEY! });

// Send the customer straight to eSewa
const session = await paybridge.checkout.create({
  amount: 10000, // NPR 100.00, in paisa
  currency: "NPR",
  provider: "esewa",
  flow: "redirect",
  returnUrl: "https://yourstore.com/order/confirm",
  customer: { name: "Sita Thapa", email: "sita@example.com" },
});

// Send the customer to session.checkout_url
// Confirm the payment from the webhook, never from the return URL
console.log(session.checkout_url);

The signing, the exact-amount status check and new IDs for retries are handled for you, and your server gets one signed payment.succeeded webhook whichever provider the customer used. Leave out both provider and flow and the customer picks eSewa, Khalti or Fonepay on a hosted page; each provider needs your own merchant account with it. Payments settle straight into your own eSewa merchant account at your own agreed rate; PayBridgeNP never holds the money.

Next Steps


Ready to accept payments in Nepal?

Connect eSewa, Khalti, and Fonepay with a single API. Free to start, with no fund-holding and no new bank accounts.