MagicPayments Integration Guides

Nepal P2P Gate

Pay-inPay-outNPReSewa

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).

OperationRailHow the integration looks
Pay-ineSewa wallet (P2P)Create an invoice, redirect the payer to the hosted page.
Pay-outeSewa wallet (phone)Server-to-server call to the phone payout endpoint.
Limits

Pay-ins accept 300 – 25,000 NPR per operation; payouts 1,500 – 25,000 NPR. In minor units that is 300002500000 and 1500002500000 respectively.

Prerequisites

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.

  1. Create the invoice Call the gate endpoint with your gate_id and the amount in NPR minor units.
  2. Redirect the payer Send the customer's browser to the invoice_url we 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.
  3. Receive the result We confirm the transfer and call your callback_url on every status change; you can poll invoice status as a fallback.
POST/api/invoice
Request body
{
  "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 transfer credentials expire

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.

POST/api/invoice/status
resp = 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.

POST/api/payment/payout/phone
Request body
{
  "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:

Operatorprovider
eSewaesewa
Python
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).

POST/api/payment/status
resp = signed_post("/api/payment/status", {
    "merchant_payment_id": "payout-np-2026-000045"
})
# resp.json()["status"] -> "success" | "processing" | "decline" | "error"
Wallet number format

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