PayBridgeNP

Developers

eSewa and Khalti error codes

Every eSewa and Khalti status and error in one place. What each means for the order, and what to do about it.

By PayBridgeNP Team7 min read

An eSewa or Khalti integration tends to fail in a handful of ways, and each provider has a short list of statuses and errors that tell you which. This page puts them in one place: what each means, what it means for the order in front of you, and what to change.

Last verified: 25 October 2026, against eSewa's ePay docs and Khalti's ePayment docs, plus the eSewa and Khalti integrations PayBridgeNP runs in production. The causes listed come from the providers' docs and from running these integrations.

The golden rule

An error or an unclear status is not the same as "the customer did not pay". Only two answers are final:

  • Paid: eSewa COMPLETE, or Khalti Completed with refunded: false and the right amount.
  • Not paid, for that attempt: eSewa NOT_FOUND or CANCELED after you have ruled out your own mistakes, or Khalti Expired or User canceled. Record it against the attempt, not the order: a newer attempt for the same order can still be paid.

Everything else, including timeouts and server errors, means "not known yet": keep the order pending and check again.

What each eSewa status or Khalti lookup answer means: complete, fulfil once; pending, check again; not found, check your own request; cancelled or expired, mark the attempt failed; refunded, do not fulfil

eSewa status check results

These come back from eSewa's status check (/api/epay/transaction/status/), which you call with the product code, transaction_uuid and total_amount.

StatuseSewa's meaningWhat it means for the orderWhat to do
COMPLETESuccessful paymentPaidCheck the amount, fulfil once, store ref_id
PENDINGInitiated but not completedNot finishedKeep pending, check again later
AMBIGUOUSPayment is in a halted stateNot knownKeep pending and check again
NOT_FOUNDTerminated at eSewa, session expiredUsually not paid, but see belowRule out your own mistakes first
CANCELEDCancelled or reversed by eSewaThis attempt is not paidMark the attempt failed
FULL_REFUNDRefunded in fullRefundedDo not fulfil
PARTIAL_REFUNDPartly refundedPartly refundedReconcile the amount
Service is currently unavailable (no status)Server connection timeoutNot knownRetry later

A few notes on that table. Failures are recorded on the attempt, not the order, so a newer attempt for the same order can still be paid. If AMBIGUOUS does not clear, contact eSewa. If a refund arrives for an order you already fulfilled, reverse the fulfilment. And the "service unavailable" answer comes back as {"code": 0, "error_message": "Service is currently unavailable"} with no status at all: never fail an order on it.

Why eSewa says NOT_FOUND for a payment that went through

Before you treat it as an unpaid order, rule out the request itself:

  • The amount is written differently. Use the exact total_amount string you put in the form. Sending 100 when the form said 100.00, or an amount in paisa, risks NOT_FOUND.
  • The wrong transaction_uuid. For example a new UUID generated on retry, while the customer paid the first one.
  • Mixed environments. Asking the test server about a live payment, or the reverse, or using EPAYTEST with a live merchant's payment.

Once those are ruled out, NOT_FOUND means the session expired unpaid, which is how eSewa describes it.

eSewa form and return problems

eSewa's payment page does not return documented error codes for a bad form, so these show up as symptoms:

SymptomLikely cause
eSewa's page refuses the payment straight awayThe signature does not match (see below)
Every attempt fails after a retry worked onceA reused transaction_uuid. Each attempt needs a new one, made of letters, numbers and hyphens only
The return arrives with no dataThe customer cancelled, or the payment failed or is still pending, on eSewa's page
The data signature does not verifyWrong secret, or the fields in the wrong order

On the way in, a mismatch usually means the wrong secret key, fields signed in a different order from signed_field_names, or an amount formatted differently from the one you signed. On the way back, build the message from eSewa's response field list in the documented order.

One more thing worth knowing: the amount inside eSewa's success response can be formatted differently from what you sent (eSewa's own example shows "1,000.0"). Use it only for checking the signature, and take the amount from your own order.

Khalti lookup results

These come back from Khalti's lookup (/epayment/lookup/), which you call with the pidx.

StatusHTTPWhat it means for the orderWhat to do
Completed200Paid, unless refunded is trueCheck total_amount, fulfil once, store transaction_id
Pending200Not finishedKeep pending, check again later
Initiated200The customer has not paid yetKeep pending until it completes or expires
Refunded / Partially Refunded200RefundedDo not fulfil
Expired400This payment link ran out unpaidMark the attempt failed
User canceled400The customer cancelled this attemptMark the attempt failed

As with eSewa, a failed or expired attempt leaves the order open for another attempt, and refunds are reconciled rather than fulfilled.

Note that Expired and User canceled come back as HTTP 400. If your code treats every 400 as an error and stops, it will never record them as failed.

Khalti errors

Validation errors on initiate

Khalti answers a bad initiate request with "error_key": "validation_error" and the field that failed:

FieldKhalti's messageFix
amount"Amount should be greater than Rs. 10, that is 1000 paisa."Send paisa, at least 1000. 100 means Rs 1
amount"A valid integer is required."Send a whole number of paisa, not "100.00"
return_url / website_url"This field may not be blank."Always send both, even for payment links and invoices
return_url / website_url"Enter a valid URL."Full, absolute URLs (use https:// in production)
purchase_order_id / purchase_order_name"This field may not be blank."Send both, short and non-empty
amount"Amount Breakdown mismatch."If you send amount_breakdown, its parts must add up to amount

Authentication errors

Khalti's messageCauseFix
"Invalid token." (401)Wrong secret key, or a sandbox key used against the live API (or the reverse)Use the key that matches the base URL
"Authentication credentials were not provided." (401)The Authorization header is missing the word KeyAuthorization: Key <secret>, not Bearer

Lookup errors

Khalti's messageCauseFix
"Not found."The pidx is wrong, or from the other environmentLook up the pidx you stored for the order. It does not mean the payment failed

Problems you will meet in testing

Some errors come up mainly in the sandboxes:

  • Khalti "insufficient balance": the shared test wallet you used has run low. Try another test ID: Khalti test credentials.
  • Khalti "similar request already being processed": an earlier request for the same payment is still open. Wait for it to finish or expire, and look it up before you try again.
  • eSewa test page not loading: the sandbox is down or slow. Wait before you change code: eSewa test credentials.

One set of errors instead of two

With PayBridgeNP, the eSewa and Khalti statuses above are handled for you: amounts are formatted per provider, a payment is only confirmed after the provider says so, and your code gets one signed payment.succeeded webhook. When something is wrong with a request, the API answers in one consistent format with a stable code you can branch on, documented in the API errors reference. Payments settle straight into your own merchant accounts.

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.