2/6 providers ready in sandbox →

Every Nepali payment gateway. One Go interface.

eSewa, Khalti, ConnectIPS, Fonepay, IME Pay and Hamro Pay behind paynp.Provider. Integer paisa, verified callbacks, and a server-side Lookup you can trust.

go get github.com/mukezhz/pay-np
checkout.go
var p paynp.Provider = khalti.New(cfg)

// 1. Start: redirect or auto-submit form
co, _ := p.Initiate(ctx, paynp.InitiateRequest{
    TxnID:      "ord-42",
    Amount:     150000, // Rs 1,500 in paisa
    SuccessURL: "https://shop.np/return",
})
co.Write(w, r)

// 2. Return: trust only Lookup
tx, err := p.Lookup(ctx, paynp.LookupRequest{
    TxnID: "ord-42", Amount: 150000,
    ProviderRef: co.ProviderRef,
})
if err == nil && tx.Status == paynp.StatusSuccess {
    fulfil(order)
}
Payment lifecycle
  1. 1
    InitiateSign the form or create the provider session.
  2. 2
    CheckoutUser pays on eSewa, Khalti, ConnectIPS…
  3. 3
    CallbackSignature checked when signed. A hint, never proof.
  4. 4
    LookupServer-to-server status. Amount must match.
Built for money

Boring where it matters.

Every adapter follows the same rules, so swapping providers never changes how you verify a payment.

Integer paisa

paynp.Paisa everywhere. Rupee strings like 1,000.0 or 10.0000 are parsed at the edge; sub-paisa is rejected.

Lookup is the truth

Unsigned callbacks never report SUCCESS. A paid transaction with the wrong amount returns ErrAmountMismatch and no transaction.

One contract

Initiate, ParseCallback, Lookup. Context, timeouts and typed *APIError on every call.

Providers

Six gateways, one shape.

Click a provider for its setup guide and env status. eSewa and Khalti run against their public sandboxes out of the box. Hamro Pay has free self-service UAT keys; the rest need merchant credentials.

Make a test payment.

2 attempts so far this session.

Open checkout