Nepal.Payments.Gateways NuGet Downloads

Easy-peasy payments gateways package for Nepal — integrate eSewa, Khalti, and Fonepay (Dynamic QR) without jhanjhat.

Features

  • eSewa payment integration
  • Khalti payment gateway
  • Fonepay Dynamic QR support
  • Unified API for all gateways
  • Async/await support
  • Callback/ webhook handling
  • Mobile and web checkout support
  • Comprehensive error handling

Installation

Terminal
dotnet add package Nepal.Payments.Gateways

Quick Start

Register Services

Program.cs
using Nepal.Payments.Gateways;
builder.Services.AddPaymentGateways(options =>
{
options.eSewa.MerchantId = "your-merchant-id";
options.eSewa.SecretKey = "your-secret-key";
options.Khalti.PublicKey = "your-public-key";
options.Khalti.SecretKey = "your-secret-key";
options.Fonepay.MerchantId = "your-merchant-id";
options.Fonepay.Password = "your-password";
});

eSewa Integration

Initialize Payment

public class PaymentController : ControllerBase
{
private readonly IEsewaService _esewaService;
public PaymentController(IEsewaService esewaService)
{
_esewaService = esewaService;
}
[HttpPost("initiate")]
public async Task<IActionResult> InitiatePayment(PaymentRequest request)
{
var response = await _esewaService.InitiatePaymentAsync(new EsewaPaymentRequest
{
Amount = request.Amount,
TaxAmount = 0,
ProductServiceCharge = 0,
ProductDeliveryCharge = 0,
TotalAmount = request.Amount,
ProductId = request.OrderId,
SuccessUrl = "https://yoursite.com/payment/success",
FailureUrl = "https://yoursite.com/payment/failure"
});
return Ok(new { paymentUrl = response.PaymentUrl });
}
}

Verify Payment

[HttpPost("verify")]
public async Task<IActionResult> VerifyPayment(string transactionId)
{
var result = await _esewaService.VerifyPaymentAsync(transactionId);
if (result.IsSuccess)
{
// Payment verified successfully
// Update your database
return Ok(new { status = "success", transaction = result.Transaction });
}
return BadRequest(new { status = "failed", message = result.Message });
}

eSewa supports both live and sandbox environments. Use sandbox for testing by setting UseSandbox = true in options.

Khalti Integration

Initialize Payment

public class KhaltiPaymentController : ControllerBase
{
private readonly IKhaltiService _khaltiService;
public KhaltiPaymentController(IKhaltiService khaltiService)
{
_khaltiService = khaltiService;
}
[HttpPost("initiate")]
public async Task<IActionResult> InitiatePayment(PaymentRequest request)
{
var response = await _khaltiService.InitiatePaymentAsync(new KhaltiPaymentRequest
{
ReturnUrl = "https://yoursite.com/payment/callback",
WebsiteUrl = "https://yoursite.com",
Amount = request.Amount * 100, // Amount in paisa
PurchaseOrderId = request.OrderId,
PurchaseOrderName = request.ProductName,
CustomerInfo = new KhaltiCustomerInfo
{
Name = request.CustomerName,
Email = request.CustomerEmail,
Phone = request.CustomerPhone
}
});
return Ok(new {
paymentUrl = response.PaymentUrl,
pidx = response.Pidx
});
}
}

Verify Khalti Payment

[HttpPost("verify")]
public async Task<IActionResult> VerifyPayment(string pidx)
{
var result = await _khaltiService.VerifyPaymentAsync(pidx);
if (result.IsSuccess && result.Status == "Completed")
{
return Ok(new { status = "success", transaction = result.TransactionId });
}
return BadRequest(new { status = "failed", message = result.Message });
}

Fonepay Integration

Generate Dynamic QR

public class FonepayController : ControllerBase
{
private readonly IFonepayService _fonepayService;
public FonepayController(IFonepayService fonepayService)
{
_fonepayService = fonepayService;
}
[HttpPost("generate-qr")]
public async Task<IActionResult> GenerateQR(PaymentRequest request)
{
var response = await _fonepayService.GenerateDynamicQRAsync(new FonepayQRRequest
{
Amount = request.Amount,
ReferenceId = request.OrderId,
ProductName = request.ProductName,
Remarks = $"Payment for {request.ProductName}"
});
return Ok(new {
qrCode = response.QRCode,
qrImage = response.QRImageUrl,
expiresAt = response.ExpiresAt
});
}
}

Verify Fonepay Payment

[HttpPost("verify")]
public async Task<IActionResult> VerifyPayment(string referenceId)
{
var result = await _fonepayService.VerifyPaymentAsync(referenceId);
if (result.IsSuccess)
{
return Ok(new {
status = "success",
transaction = result.Transaction
});
}
return BadRequest(new { status = "failed" });
}

Fonepay Dynamic QR allows customers to scan and pay from any banking app that supports Fonepay.

Unified API

Use a single interface for all gateways:

public class UnifiedPaymentController : ControllerBase
{
private readonly IPaymentGatewayFactory _factory;
public UnifiedPaymentController(IPaymentGatewayFactory factory)
{
_factory = factory;
}
[HttpPost("pay/{gateway}")]
public async Task<IActionResult> Pay(string gateway, PaymentRequest request)
{
var service = _factory.GetGateway(gateway);
var response = await service.InitiatePaymentAsync(new PaymentInitiationRequest
{
Amount = request.Amount,
OrderId = request.OrderId,
SuccessUrl = "https://yoursite.com/success",
FailureUrl = "https://yoursite.com/failure"
});
return Ok(new { paymentUrl = response.PaymentUrl });
}
}

Configuration Options

builder.Services.AddPaymentGateways(options =>
{
// eSewa Configuration
options.Esewa.MerchantId = "EPAYTEST"; // Test merchant
options.Esewa.SecretKey = "8gBm/:&EnhH.1/q";
options.Esewa.UseSandbox = true; // Set to false for production
// Khalti Configuration
options.Khalti.PublicKey = "test_public_key";
options.Khalti.SecretKey = "test_secret_key";
options.Khalti.UseSandbox = true;
// Fonepay Configuration
options.Fonepay.MerchantId = "TEST123";
options.Fonepay.Password = "Test@123";
options.Fonepay.UseSandbox = true;
});

Never commit production credentials to source control. Use environment variables or Azure Key Vault.

Using Environment Variables

builder.Services.AddPaymentGateways(options =>
{
options.Esewa.MerchantId = Environment.GetEnvironmentVariable("ESEWA_MERCHANT_ID")!;
options.Esewa.SecretKey = Environment.GetEnvironmentVariable("ESEWA_SECRET_KEY")!;
options.Esewa.UseSandbox = false;
options.Khalti.PublicKey = Environment.GetEnvironmentVariable("KHALTI_PUBLIC_KEY")!;
options.Khalti.SecretKey = Environment.GetEnvironmentVariable("KHALTI_SECRET_KEY")!;
options.Fonepay.MerchantId = Environment.GetEnvironmentVariable("FONEPAY_MERCHANT_ID")!;
options.Fonepay.Password = Environment.GetEnvironmentVariable("FONEPAY_PASSWORD")!;
});

Callback/Webhook Handling

[HttpPost("callback/{gateway}")]
public async Task<IActionResult> PaymentCallback(string gateway, [FromBody] PaymentCallback callback)
{
var service = _factory.GetGateway(gateway);
var result = await service.HandleCallbackAsync(callback);
if (result.IsVerified)
{
// Update order status
await _orderService.MarkAsPaid(result.OrderId, result.TransactionId);
return Ok();
}
return BadRequest();
}

Error Handling

try
{
var response = await _esewaService.InitiatePaymentAsync(request);
return Ok(response);
}
catch (PaymentGatewayException ex)
{
// Gateway-specific error
_logger.LogError(ex, "Payment failed for order {OrderId}", request.ProductId);
return BadRequest(new { error = ex.Message, code = ex.ErrorCode });
}
catch (Exception ex)
{
_logger.LogError(ex, "Unexpected error during payment");
return StatusCode(500, "An error occurred");
}

API Reference

IEsewaService

MethodDescription
InitiatePaymentAsyncStart a new payment
VerifyPaymentAsyncVerify payment status
GetTransactionAsyncGet transaction details

IKhaltiService

MethodDescription
InitiatePaymentAsyncStart ePayment
VerifyPaymentAsyncVerify by pidx
GetTransactionAsyncGet transaction details

IFonepayService

MethodDescription
GenerateDynamicQRAsyncGenerate QR code
VerifyPaymentAsyncCheck payment status
GetTransactionAsyncGet transaction details

Testing

Use these test credentials in sandbox:

GatewayTest Credential
eSewaID: 9806800001/2/3/4/5
KhaltiUse test keys from dashboard
FonepayContact Fonepay for test credentials

Support