Nepal P2P Gate
Accept eSewa wallet pay-ins on a hosted page and send eSewa payouts in Nepalese Rupee (NPR).
When to use it
The Nepal P2P Gate accepts eSewa wallet pay-ins on a MagicPayments-hosted page —
the payer is shown an eSewa wallet number to transfer to — and sends eSewa payouts
to a wallet number. All amounts are in NPR (Nepalese Rupee, 2 decimal places — so
30100 means 301.00 NPR).
| Operation | Rail | How the integration looks |
|---|---|---|
| Pay-in | eSewa wallet (P2P) | Create an invoice, redirect the payer to the hosted page. |
| Pay-out | eSewa wallet (phone) | Server-to-server call to the phone payout endpoint. |
Pay-ins accept 300 – 25,000 NPR per operation; payouts
1,500 – 25,000 NPR. In minor units that is 30000–2500000
and 150000–2500000 respectively.
You need your signing credentials from Getting started, a
pay-in gate_id for Nepal eSewa, and a pay-out
cascade_id enabled for NPR eSewa payouts. Your account manager provides both.
Pay-in — hosted eSewa page
The payer never touches your servers with their payment details. You create an invoice; we host the page.
-
Create the invoice
Call the gate endpoint with your
gate_idand the amount in NPR minor units. -
Redirect the payer
Send the customer's browser to the
invoice_urlwe return. Our page shows the recipient eSewa wallet number and the exact amount; the payer completes the transfer in their eSewa app and confirms on the page. -
Receive the result
We confirm the transfer and call your
callback_urlon every status change; you can poll invoice status as a fallback.
/api/invoice{
"gate_id": "np-esewa-gate",
"invoice": {
"invoice_id": "order-np-2026-000123",
"currency": "NPR",
"amount": 30100,
"description": "Wallet top-up",
"ttl_minutes": 30
},
"customer": {
"id": "cust-88130",
"full_name": "Suman Shrestha",
"phone_number": "+9779800000001"
},
"workflow_hooks": {
"callback_url": "https://merchant.example.com/mp/callbacks",
"return_success_url": "https://merchant.example.com/orders/123/done",
"return_decline_url": "https://merchant.example.com/orders/123/retry"
}
}
Python
resp = signed_post("/api/invoice", {
"gate_id": "np-esewa-gate",
"invoice": {
"invoice_id": "order-np-2026-000123",
"currency": "NPR",
"amount": 30_100, # 301.00 NPR (2 decimal places)
"description": "Wallet top-up",
"ttl_minutes": 30,
},
"customer": {
"id": "cust-88130",
"full_name": "Suman Shrestha",
"phone_number": "+9779800000001",
},
"workflow_hooks": {
"callback_url": "https://merchant.example.com/mp/callbacks",
"return_success_url": "https://merchant.example.com/orders/123/done",
"return_decline_url": "https://merchant.example.com/orders/123/retry",
},
})
invoice = resp.json()
redirect_url = invoice["invoice_url"] # send the payer here
Response
{
"request_id": "0f0b1d2e-...",
"request_status": "success",
"invoice_id": "62051f64-9a79-4edb-8a9e-95c86c55ee4e",
"merchant_invoice_id": "order-np-2026-000123",
"invoice_status": "unpaid",
"invoice_url": "https://stage.example-mp.com/public/invoice/62051f64-.../gate",
"message": "Invoice (Gate PayIn) with internal uid=62051f64-... has been created."
}
The recipient wallet number our page shows is reserved for a limited window (typically ~9 minutes)
and the page shows the payer a countdown. Set a ttl_minutes that gives the payer time to
complete the transfer in the eSewa app, and lean on the callback rather than tight polling.
Tracking the pay-in
Look up the invoice by your own id (or our invoice_uid). It reaches paid on success.
/api/invoice/statusresp = signed_post("/api/invoice/status", {
"merchant_invoice_id": "order-np-2026-000123"
})
invoice = resp.json()
# invoice["status"] -> "paid" | "payment_failed" | "expired" | "canceled" | ...
# invoice["actual_payment"]["processing_info"]["amount_acquired"] -> settled NPR minor units
Pay-out — to an eSewa wallet
Payouts go server-to-server. The destination is the recipient's eSewa wallet number
(their mobile number). Use the phone payout endpoint with a cascade_id enabled for NPR payouts.
/api/payment/payout/phone{
"cascade_id": "np-esewa-payout",
"payment": {
"payment_id": "payout-np-2026-000045",
"currency": "NPR",
"amount": 150000,
"description": "Affiliate payout"
},
"phone": {
"provider": "esewa",
"phone_number": "+9779800000002"
},
"customer": {
"id": "partner-2391",
"full_name": "Anita Gurung"
},
"workflow_hooks": {
"callback_url": "https://merchant.example.com/mp/callbacks"
}
}
The phone.provider names the wallet operator. Supported here:
| Operator | provider |
|---|---|
| eSewa | esewa |
resp = signed_post("/api/payment/payout/phone", {
"cascade_id": "np-esewa-payout",
"payment": {
"payment_id": "payout-np-2026-000045",
"currency": "NPR",
"amount": 150_000, # 1,500.00 NPR — the payout minimum
"description": "Affiliate payout",
},
"phone": {"provider": "esewa", "phone_number": "+9779800000002"},
"customer": {"id": "partner-2391", "full_name": "Anita Gurung"},
"workflow_hooks": {"callback_url": "https://merchant.example.com/mp/callbacks"},
})
payout = resp.json()
payout_uid = payout["payment_id"] # our uid; status starts at "initiated"
Tracking the pay-out
Payouts use the payment status endpoint (not the invoice one).
/api/payment/statusresp = signed_post("/api/payment/status", {
"merchant_payment_id": "payout-np-2026-000045"
})
# resp.json()["status"] -> "success" | "processing" | "decline" | "error"
Send the destination in international format (+977…) or as the local 10-digit mobile
number registered with eSewa. A number not registered with eSewa is the most common cause of a
decline on payout.
Testing & go-live
- On stage, use the test
gate_id/cascade_idfrom your account manager; no real funds move. - Verify you can drive a pay-in to
paidand a payout tosuccess, and that your callback handler verifies the signature and is idempotent. - Confirm your NPR amount conversion:
amountis minor units with 2 decimal places. - Stay inside the limits: pay-in 300–25,000 NPR, payout 1,500–25,000 NPR per operation.
- Swap base URL and credentials to production; the request shapes are identical.