Use the adapters directly
Each language has the same shape: build the configured providers from environment variables, call initiate() to start a payment, then call verify() from your return handler with the values you stored. All amounts are integer paisa (1 NPR = 100 paisa).
1. Copy the adapter
Section titled “1. Copy the adapter”| Language | Copy | Notes |
|---|---|---|
| TypeScript | scripts/ts/src/ |
Keep core.ts, index.ts and the providers you need. Files import each other with .ts extensions; rewrite to .js for NodeNext or extensionless for bundlers if your tsconfig lacks allowImportingTsExtensions. |
| Python | scripts/python/nepal_payments/ |
Stdlib only. Add cryptography for connectIPS. |
| Java | scripts/java/src/main/java/np/payments/ |
JDK 17+, no dependencies, blocking and thread-safe. |
| Kotlin | scripts/kotlin/src/main/kotlin/np/payments/ |
kotlin-stdlib only, suspend API. Server side only, never inside an Android app. |
| PHP | scripts/php/src/ |
Namespace NepalPayments. Register it in your PSR-4 autoload. |
| Go | scripts/go/payments/ |
Stdlib only. Copy into your module, for example internal/payments/, and fix the import path. |
2. Configure
Section titled “2. Configure”Set the environment variables for each provider you want. A provider is enabled when its required variables are present. The full list is in Environment variables.
ESEWA_ENV=sandboxESEWA_PRODUCT_CODE=EPAYTESTESEWA_SECRET_KEY='8gBm/:&EnhH.1/q'KHALTI_SECRET_KEY=... # from test-admin.khalti.comKHALTI_WEBSITE_URL=https://shop.example.com3. Initiate and verify
Section titled “3. Initiate and verify”import { createPayments, paymentsConfigFromEnv, newOrderId } from "./payments/index.ts";
const payments = createPayments(paymentsConfigFromEnv());const init = await payments.get("khalti").initiate({ orderId: newOrderId(), amountPaisa: 150000, description: "Order #42", returnUrl: "https://shop.example.com/payments/khalti/return",});
// later, in the return handler: verify with values from YOUR databaseconst result = await payments.get("khalti").verify({ orderId: attempt.id, amountPaisa: attempt.amountPaisa, providerRef: attempt.providerRef,});from nepal_payments import create_payments, config_from_env, new_order_id
payments = create_payments(config_from_env())init = payments["khalti"].initiate( order_id=new_order_id(), amount_paisa=150000, description="Order #42", return_url="https://shop.example.com/payments/khalti/return",)
# later, in the return handler: verify with values from YOUR databaseresult = payments["khalti"].verify(attempt.id, attempt.amount_paisa, provider_ref=attempt.provider_ref)p, err := payments.New(payments.ConfigFromEnv())if err != nil { log.Fatal(err)}init, err := p.Khalti.Initiate(ctx, payments.InitiateInput{ OrderID: payments.NewOrderID(), AmountPaisa: 150000, Description: "Order #42", ReturnURL: "https://shop.example.com/payments/khalti/return",})
// later, in the return handler: verify with values from YOUR databaseres, err := p.Khalti.Verify(ctx, payments.VerifyInput{ OrderID: a.ID, AmountPaisa: a.AmountPaisa, ProviderRef: a.ProviderRef,})Payments payments = Payments.create(Payments.configFromEnv());InitiateResult init = payments.khalti().initiate(InitiateInput.of( Payments.newOrderId(), 150_000, "Order #42", "https://shop.example.com/payments/khalti/return"));
// later, in the return handler: verify with values from YOUR databaseVerifyResult result = payments.khalti().verify( new VerifyInput(attempt.id(), attempt.amountPaisa(), attempt.providerRef(), null));val payments = Payments.create(paymentsConfigFromEnv())val init = payments.khalti.initiate(InitiateInput( orderId = newOrderId(), amountPaisa = 150_000, description = "Order #42", returnUrl = "https://shop.example.com/payments/khalti/return",))
// later, in the return handler (suspend): verify with values from YOUR databaseval result = payments.khalti.verify(VerifyInput(attempt.id, attempt.amountPaisa, providerRef = attempt.providerRef))use NepalPayments\{InitiateInput, Payments, VerifyInput};
$payments = Payments::create(Payments::configFromEnv());$init = $payments->khalti()->initiate(new InitiateInput( orderId: Payments::newOrderId(), amountPaisa: 150000, description: 'Order #42', returnUrl: 'https://shop.example.com/payments/khalti/return',));
// later, in the return handler: verify with values from YOUR database$result = $payments->khalti()->verify(new VerifyInput($attempt->id, $attempt->amountPaisa, $attempt->providerRef));initiate() returns either a redirect (send the browser to url) or a form (render an auto-submitting POST; every port has a renderAutoSubmitForm helper). Store the providerRef it returns on the attempt: Khalti’s pidx, NPS’s ProcessId and IME Pay’s token are needed by verify().
4. Wire the routes
Section titled “4. Wire the routes”Every framework needs the same five routes. Web frameworks has complete handlers for Express, Hono, Next.js, FastAPI, Django, Laravel, Spring Boot and Ktor, plus notes for Go net/http, chi and Gin. Mobile apps reuse those routes; see Mobile apps.