Accept Online Payments in Nepal: eSewa and Khalti Integration

Khimananda Oli 8 min read Database
Accept Online Payments in Nepal: eSewa and Khalti Integration

By Khimananda Oli | Last reviewed: August 2026

If you are building a SaaS platform or e-commerce store targeting Nepali customers, you must accept online payments in Nepal: eSewa and Khalti integration is effectively mandatory. While international gateways like Stripe remain inaccessible for domestic NPR transactions, these two wallets dominate the local market with over 90% combined digital wallet share. This guide provides the architectural patterns, security validations, and implementation details needed to integrate them reliably into your application stack.

How Do You Architect Secure Payment Flows for eSewa and Khalti?

Payment integration fails when developers treat the frontend redirect as the source of truth. A robust architecture for accept online payments in Nepal: eSewa and Khalti integration always centers on server-to-server validation. The browser merely initiates the flow; your backend confirms it. Whether you are deploying on a Laravel VPS setup or a Node.js container, the sequence remains identical.

User BrowserMerchant Server(Signature + DB)eSewa / KhaltiPayment Gateway1. Initiate Order2. Redirect URL3. User Pays4. Webhook/IPN
Figure 1: Secure server-centric flow for accepting online payments in Nepal via eSewa and Khalti

The critical path involves four distinct phases. First, your server generates a signed request containing the amount, transaction UUID, and callback URLs. Second, the user is redirected to the wallet’s hosted checkout or completes payment via SDK. Third—and most importantly—the gateway sends an asynchronous IPN (Instant Payment Notification) or webhook directly to your backend. Fourth, your server verifies the signature against your secret key before updating order status. Never skip step three. Client-side JavaScript can be manipulated; server-side HMAC verification cannot.

Environment Configuration Best Practices

Store credentials outside your codebase. For teams managing infrastructure with Terraform or similar IaC tools, inject secrets via environment variables or a vault at deploy time. Your .env should contain:

ESEWA_MERCHANT_ID=EPAYTEST
ESEWA_SECRET_KEY=8gBm/:&EnhH.1/q
KHALTI_PUBLIC_KEY=test_public_key_xxxx
KHALTI_SECRET_KEY=test_secret_key_yyyy
PAYMENT_WEBHOOK_URL=https://api.yoursite.com/payments/verify

Always use separate keys for sandbox and production. Test transactions in sandbox do not move real money but exercise the exact same verification logic you will rely on during peak sales periods.

What Are the Key Differences Between eSewa and Khalti APIs?

Choosing between providers—or deciding to support both—requires understanding their technical trade-offs. Both allow you to accept online payments in Nepal: eSewa and Khalti integration differs primarily in authentication style, webhook reliability, and ecosystem reach.

CriteriaeSewaKhalti
AuthenticationHMAC-SHA256 SignatureBearer Token / API Key
Verification MethodIPN POST + Signature CheckServer-Side Lookup API
Sandbox StabilityModerate (occasional downtime)High (consistent test env)
User Base (2026)Larger mass-market adoptionStronger urban/youth demographic
Documentation QualityAdequate but dated examplesModern REST docs + SDKs
Settlement TimeT+1 to T+2 business daysT+1 business days

In practice, eSewa’s signature-based approach feels more traditional but aligns well with banking-grade audit trails. Khalti’s lookup-based verification simplifies initial coding but adds an extra API call per transaction. I recommend integrating both if your revenue depends on conversion rate; dropping either leaves 30–40% of potential customers without their preferred payment method.

How Do You Implement Server-Side Verification Correctly?

This is where most integrations fail silently. Developers see a "success" screen and mark orders paid without cryptographic proof. When you accept online payments in Nepal: eSewa and Khalti integration demands rigorous backend validation.

GatewayYour ServerDatabasePOST /webhook (signed)Verify SigCheck AmtUPDATE orders SET status='paid'HTTP 200 OKLog Audit
Figure 2: Mandatory webhook verification sequence when you accept online payments in Nepal

eSewa Signature Verification Example

eSewa signs payloads using HMAC-SHA256. Reconstruct the message string exactly as documented, then compare:

import hmac, hashlib, base64

def verify_esewa_signature(payload: dict, secret: str) -> bool:
    message = f"transaction_code={payload['transaction_code']},status={payload['status']},total_amount={payload['total_amount']}"
    expected = base64.b64encode(
        hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(expected, payload.get('signature', ''))

Note the use of hmac.compare_digest instead of ==. This prevents timing attacks that could leak signature bytes. Always validate total_amount matches your stored order value—never trust the amount sent by the gateway alone.

Khalti Verification Lookup Pattern

Khalti uses a simpler token-authenticated lookup. After receiving the pidx from the client or webhook, query their verification endpoint server-side:

import requests

def verify_khalti_payment(pidx: str, secret_key: str, expected_amount: int) -> dict | None:
    resp = requests.post(
        "https://khalti.com/api/v2/payment/lookup/",
        headers={"Authorization": f"Key {secret_key}"},
        json={"pidx": pidx},
        timeout=10
    )
    if resp.status_code != 200:
        return None
    data = resp.json()
    if data.get("status") == "Completed" and data.get("total_amount") == expected_amount:
        return data
    return None

Cache negative results briefly to avoid hammering the API during retry storms, but never cache successful verifications across different requests. Each transaction must be validated independently.

How Should You Handle Webhook Failures and Idempotency?

Networks in Nepal can be unpredictable. Gateways may retry webhooks, or your server might acknowledge receipt but crash before writing to disk. Designing for failure is non-negotiable when you accept online payments in Nepal: eSewa and Khalti integration must survive real-world conditions.

  • Idempotent Processing: Store each transaction ID in a dedicated payment_events table with a unique constraint. Before processing any webhook, check if that ID already exists. If yes, return 200 immediately without re-updating the order.
  • Atomic Updates: Wrap verification and order status changes in a single database transaction. Partial states cause orphaned payments and customer support nightmares.
  • Retry Logic: Return HTTP 200 only after successful persistence. Return 5xx for transient failures so the gateway retries. Configure exponential backoff awareness—most Nepali gateways retry at 1min, 5min, 30min intervals.
  • Audit Logging: Log every raw webhook payload before processing. When disputes arise (and they will), having immutable request logs saves hours of reconciliation. Teams using Prometheus and Grafana should expose webhook latency and failure rates as metrics.

A common mistake is returning 200 prematurely because the framework auto-responds before your async handler finishes. In Laravel, use synchronous jobs or database transactions within the controller. In Node.js, await the DB write before sending the response. Async fire-and-forget patterns lose payments.

❌ Fragile Pattern• Trust client-side success• No idempotency checks• Async fire-and-forget• Amount not revalidated• No audit trailLost Payments & Fraud Risk✅ Production-Ready Pattern• Server-side HMAC verify• Unique TX ID constraint• Sync DB write before 200• Amount cross-checked• Raw payload loggingAudit-Ready & Reliable
Figure 3: Fragile vs production-ready approaches to accept online payments in Nepal

When Is Dual-Gateway Integration Worth the Complexity?

Supporting both eSewa and Khalti increases maintenance burden but significantly improves conversion. My rule of thumb: if monthly transaction volume exceeds NPR 500,000 or your user base spans multiple demographics, dual integration pays for itself within weeks. For early-stage MVPs serving Kathmandu-centric tech users, Khalti alone may suffice initially. For mass-market goods, government services, or remittance-adjacent products, eSewa is non-negotiable.

Abstract the gateway behind a unified interface. Create a PaymentProvider contract with initiate(), verify(), and refund() methods. Concrete implementations handle provider-specific quirks. This lets you add IME Pay or Fonepay later without rewriting business logic. Teams already practicing clean architecture through REST API design with Sanctum will find this pattern natural.

Compliance and Security Reminders

Nepal Rastra Bank regulations require merchants to retain transaction records for five years. Ensure your database retention policies align. Never log full card numbers or wallet PINs. Mask sensitive fields in logs. If you handle recurring billing, obtain explicit user consent per NRB directives. Security isn’t optional—it’s the foundation of trust in Nepal’s growing digital economy.

Next Steps for Production Deployment

You now have the architectural blueprint to accept online payments in Nepal: eSewa and Khalti integration done correctly. Start with sandbox testing, implement idempotent webhook handlers, and verify every transaction server-side before marking orders complete. Monitor failure rates closely during your first month—gateway behavior in production often differs from documentation.

If your team needs hands-on implementation support, security review, or help designing a scalable payment microservice, reach out directly. I’ve helped Nepali startups and enterprises build audit-ready payment systems that handle peak loads without losing a single rupee. Let’s make sure yours does too.

Frequently Asked Questions

Both gateways typically charge merchants between 1.5% and 2% per successful transaction. Exact rates depend on your business category and negotiated volume tiers. Always verify the latest fee structure directly in the merchant dashboard before integrating, as pricing updates frequently without public announcements.

Yes. Both payment gateways require valid PAN or VAT registration and business documents for merchant account approval. Individual developers cannot obtain production API credentials without legal business entity verification through their respective compliance teams.

Khalti offers an official Composer package supporting Laravel 11 and PHP 8.3. eSewa relies mostly on community-maintained packages that may lag behind framework updates. For production Laravel applications in 2026, Khalti generally provides smoother integration with active maintenance and documented endpoints.

Approval usually takes three to seven business days after submitting complete documentation. Delays occur if KYC documents are unclear or business categories require additional compliance review. Start the application process well before your planned launch date to avoid integration bottlenecks.

Yes. Both platforms provide sandbox environments with test credentials and dummy card numbers. Use these extensively during development to verify webhook handling, refund flows, and error states before requesting production keys.

Absolutely. Never rely solely on client-side success callbacks. Configure server-to-server webhooks to confirm transaction status independently. This prevents fraud where users manipulate frontend responses to fake successful payments without actual fund transfers completing.

No. eSewa currently processes only NPR transactions from Nepali bank accounts and wallets. International customers must use alternative gateways like Stripe or PayPal. Khalti also restricts processing to domestic NPR payments within Nepal's banking ecosystem.

Implement idempotent verification logic using unique transaction IDs. Log all gateway responses and retry verification up to three times with exponential backoff. If verification consistently fails, mark orders as pending and alert support rather than auto-failing legitimate customer purchases.

Both gateways mandate HTTPS with TLS 1.2 or higher on all callback URLs. Ensure your certificate is valid and properly chained. Self-signed certificates will be rejected during webhook delivery and API authentication in both sandbox and production environments.

Never store raw card or wallet credentials. Both eSewa and Khalti use tokenization for recurring payments. Store only the returned payment tokens and reference IDs. Local storage of sensitive financial data violates PCI-DSS requirements and gateway terms of service.

Implement circuit breaker patterns to detect sustained API failures. Queue payment requests for automatic retry once services recover. Display clear messaging to customers suggesting alternative payment methods during outages rather than showing generic server errors.

Both APIs support partial and full refunds via authenticated POST requests. Refunds typically process within 24-48 hours. Track refund status through webhooks since synchronous responses only confirm request acceptance, not completion. Always validate refund eligibility against original transaction age limits.

Yes for businesses exceeding 500 monthly transactions. Redundancy reduces revenue loss during single-gateway outages. However, maintaining two integrations increases testing overhead and reconciliation complexity. Evaluate your transaction volume and uptime requirements before committing to multi-gateway architecture.

Both gateways accept amounts in paisa as integers, not decimal rupees. Multiply all NPR values by 100 before sending API requests. Sending decimal amounts causes silent truncation or rejection errors that are difficult to debug without careful logging.

Download settlement reports via API or dashboard each morning. Match gateway transaction IDs against your order database to identify discrepancies. Automate this reconciliation process since manual matching becomes unmanageable beyond fifty daily transactions and catches failed webhook deliveries promptly.