| Crates.io | rustpayment |
| lib.rs | rustpayment |
| version | 0.1.1 |
| created_at | 2025-11-16 06:09:19.999143+00 |
| updated_at | 2025-11-16 09:48:18.489465+00 |
| description | A Rust library for integrating eSewa payment gateway - supports payment initiation, signature generation, and response validation |
| homepage | |
| repository | https://github.com/bivekk51/rust-neppayments |
| max_upload_size | |
| id | 1935254 |
| size | 101,438 |
A Rust library for integrating eSewa payment gateway into your applications. This library provides a simple, type-safe API for initiating payments, generating HMAC signatures, and validating payment responses.
tokio and reqwest for async operationsAdd this to your Cargo.toml:
[dependencies]
rustpayment = { path = "." } # Or version number when published
tokio = { version = "1", features = ["full"] }
use rustpayment::{
pay_with_esewa,
generate_signature,
validate_esewa_response,
generate_transaction_uuid,
EsewaPaymentRequest,
EsewaEnvironment,
};
#[tokio::main]
async fn main() {
// Your eSewa merchant secret key
let secret_key = "8gBm/:&EnhH.1/q";
// Create a payment request
let request = EsewaPaymentRequest {
amount: "100".to_string(),
tax_amount: "10".to_string(),
total_amount: "110".to_string(),
transaction_uuid: generate_transaction_uuid(),
product_code: "EPAYTEST".to_string(),
product_service_charge: "0".to_string(),
product_delivery_charge: "0".to_string(),
success_url: "http://yoursite.com/success".to_string(),
failure_url: "http://yoursite.com/failure".to_string(),
signed_field_names: "total_amount,transaction_uuid,product_code".to_string(),
};
// Initiate payment (use `EsewaEnvironment::Production` for real integration)
match pay_with_esewa(request, secret_key, EsewaEnvironment::Sandbox).await {
Ok(payment_url) => {
println!("Redirect user to: {}", payment_url);
}
Err(e) => {
eprintln!("Payment error: {}", e);
}
}
}
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use rustpayment::{
generate_transaction_uuid, pay_with_esewa, validate_esewa_response, EsewaPaymentRequest,
};
use serde::Deserialize;
const SECRET_KEY: &str = "8gBm/:&EnhH.1/q";
#[derive(Deserialize)]
struct SuccessQuery {
data: String,
}
#[get("/pay")]
async fn initiate_payment() -> impl Responder {
let request = EsewaPaymentRequest {
amount: "100".to_string(),
tax_amount: "10".to_string(),
total_amount: "110".to_string(),
transaction_uuid: generate_transaction_uuid(),
product_code: "EPAYTEST".to_string(),
product_service_charge: "0".to_string(),
product_delivery_charge: "0".to_string(),
success_url: "http://127.0.0.1:8080/success".to_string(),
failure_url: "http://127.0.0.1:8080/failure".to_string(),
signed_field_names: "total_amount,transaction_uuid,product_code".to_string(),
};
match pay_with_esewa(request, SECRET_KEY, EsewaEnvironment::Sandbox).await {
Ok(payment_url) => HttpResponse::Found()
.append_header(("Location", payment_url))
.finish(),
Err(e) => HttpResponse::InternalServerError()
.body(format!("Payment error: {}", e)),
}
}
#[get("/success")]
async fn payment_success(query: web::Query<SuccessQuery>) -> impl Responder {
match validate_esewa_response(&query.data, SECRET_KEY) {
Ok(result) => {
if result.signature_valid {
HttpResponse::Ok().json(serde_json::json!({
"status": "success",
"transaction_code": result.response.transaction_code,
"amount": result.response.total_amount,
}))
} else {
HttpResponse::BadRequest().json(serde_json::json!({
"status": "error",
"message": "Invalid signature"
}))
}
}
Err(e) => HttpResponse::BadRequest()
.body(format!("Validation error: {}", e)),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(initiate_payment)
.service(payment_success)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
generate_signatureGenerates an HMAC-SHA256 signature for eSewa payment authentication.
pub fn generate_signature(
total_amount: &str,
transaction_uuid: &str,
product_code: &str,
secret_key: &str,
) -> String
Parameters:
total_amount - Total payment amount as stringtransaction_uuid - Unique transaction identifierproduct_code - eSewa product code (e.g., "EPAYTEST")secret_key - Merchant secret key provided by eSewaReturns: Base64-encoded HMAC-SHA256 signature
Example:
let signature = generate_signature("110", "id-123-abc", "EPAYTEST", "your_secret_key");
pay_with_esewaInitiates a payment with eSewa and returns the redirect URL.
pub async fn pay_with_esewa(
request: EsewaPaymentRequest,
secret_key: &str,
) -> Result<String, PaymentError>
Parameters:
request - Payment request detailssecret_key - Merchant secret keyReturns: Result<String, PaymentError> - Payment URL on success
Example:
let request = EsewaPaymentRequest { /* ... */ };
let url = pay_with_esewa(request, "secret").await?;
validate_esewa_responseValidates and decodes eSewa payment response.
pub fn validate_esewa_response(
encoded_data: &str,
secret_key: &str,
) -> Result<ValidationResult, PaymentError>
Parameters:
encoded_data - Base64-encoded JSON data from eSewa callbacksecret_key - Merchant secret keyReturns: Result<ValidationResult, PaymentError> containing decoded data and signature validity
Example:
let result = validate_esewa_response(encoded_data, "secret")?;
if result.signature_valid {
println!("Payment verified: {}", result.response.transaction_code);
}
generate_transaction_uuidGenerates a unique transaction identifier.
pub fn generate_transaction_uuid() -> String
Returns: UUID in format id-<milliseconds>-<random>
Example:
let uuid = generate_transaction_uuid();
// Example: "id-1763263100223-b26yhc0gy"
EsewaPaymentRequestpub struct EsewaPaymentRequest {
pub amount: String,
pub tax_amount: String,
pub total_amount: String,
pub transaction_uuid: String,
pub product_code: String,
pub product_service_charge: String,
pub product_delivery_charge: String,
pub success_url: String,
pub failure_url: String,
pub signed_field_names: String,
}
EsewaPaymentResponsepub struct EsewaPaymentResponse {
pub transaction_code: String,
pub status: String,
pub total_amount: String,
pub transaction_uuid: String,
pub product_code: String,
pub signed_field_names: String,
pub signature: String,
}
ValidationResultpub struct ValidationResult {
pub signature_valid: bool,
pub response: EsewaPaymentResponse,
}
PaymentErrorpub enum PaymentError {
NetworkError(String),
InvalidResponse(String),
SignatureError(String),
DecodeError(String),
}
Run the test suite:
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_signature_generation
# Run integration tests only
cargo test --test integration_tests
The library includes:
A complete web server example is included in src/main.rs. Run it with:
cargo run
Then visit http://127.0.0.1:8080 to test the payment flow.
For production use, consider storing sensitive data in environment variables:
use std::env;
let secret_key = env::var("ESEWA_SECRET_KEY")
.expect("ESEWA_SECRET_KEY must be set");
Product Code: EPAYTEST
Secret Key: 8gBm/:&EnhH.1/q
Environment: https://rc-epay.esewa.com.np/
signature_valid before processing paymentsmatch pay_with_esewa(request, secret_key).await {
Ok(url) => {
// Success - redirect user
}
Err(PaymentError::NetworkError(e)) => {
// Handle network errors (retry logic)
}
Err(PaymentError::InvalidResponse(e)) => {
// Handle invalid API responses
}
Err(e) => {
// Handle other errors
}
}
reqwest - HTTP client for API requestshmac & sha2 - HMAC-SHA256 signature generationbase64 - Base64 encoding/decodingserde & serde_json - JSON serializationrand - Random UUID generationContributions are welcome! Please:
cargo test)MIT License - See LICENSE file for details
For issues and questions:
Made with for the Rust community