A full-stack payment integration system for eSewa (Nepal's digital wallet) built with Django REST Framework (Backend) and React + Vite (Frontend).
- Overview
- Features
- Tech Stack
- Project Structure
- Prerequisites
- Installation
- Configuration
- API Documentation
- Usage
- How It Works
- Security
- Contributing
This project demonstrates a complete eSewa payment integration workflow, including:
- Payment initialization with HMAC-SHA256 signature generation
- Secure payment form submission to eSewa gateway
- Payment callback handling and verification
- Beautiful UI with payment status display
- ๐ Secure Payment Processing: HMAC-SHA256 signature generation for payment authentication
- ๐ณ eSewa Integration: Full integration with eSewa's v2 API
- โ๏ธ Modern Frontend: React 19 with Vite for fast development
- ๐จ Tailwind CSS: Beautiful, responsive UI components
- ๐ Payment Verification: Automatic payment status verification and display
- ๐ฑ Mobile Responsive: Works seamlessly on all devices
- ๐ RESTful API: Django REST Framework backend with clean API endpoints
- Python 3.x
- Django 5.2.6 - Web framework
- Django REST Framework 3.16.1 - API development
- django-cors-headers 4.7.0 - CORS handling
- python-decouple 3.8 - Environment variable management
- React 19.1.1 - UI library
- Vite 7.1.2 - Build tool
- React Router DOM 7.8.2 - Routing
- Axios 1.11.0 - HTTP client
- Tailwind CSS 4.1.13 - Styling
- Lucide React 0.543.0 - Icons
esewa-integration/
โโโ backend/
โ โโโ manage.py
โ โโโ db.sqlite3
โ โโโ core/
โ โ โโโ __init__.py
โ โ โโโ admin.py
โ โ โโโ apps.py
โ โ โโโ models.py
โ โ โโโ views.py # Payment API views
โ โ โโโ urls.py # API endpoints
โ โ โโโ utils.py # Signature generation utilities
โ โโโ myproject/
โ โ โโโ __init__.py
โ โ โโโ settings.py # Django settings
โ โ โโโ urls.py
โ โ โโโ wsgi.py
โ โโโ esewa-env/ # Virtual environment
โ
โโโ frontend/
โโโ package.json
โโโ vite.config.js
โโโ index.html
โโโ src/
โ โโโ main.jsx
โ โโโ App.jsx
โ โโโ components/
โ โ โโโ payments/
โ โ โโโ EsewaPaymentForm.jsx
โ โโโ pages/
โ โ โโโ Home.jsx
โ โ โโโ PaymentResult.jsx
โ โโโ services/
โ โ โโโ paymentService.js
โ โโโ config/
โ โ โโโ api.js
โ โโโ routes/
โ โโโ AppRoutes.jsx
โโโ public/
- Python 3.8 or higher
- Node.js 18.x or higher
- npm or yarn package manager
- eSewa Merchant Account (for production) or Test Credentials
-
Navigate to backend directory:
cd backend -
Create and activate virtual environment:
python -m venv esewa-env # On Windows esewa-env\Scripts\activate # On macOS/Linux source esewa-env/bin/activate
-
Install dependencies:
pip install django djangorestframework django-cors-headers python-decouple
-
Create
.envfile in thebackenddirectory:DJANGO_SECRET_KEY=your-django-secret-key-here DEBUG=True # eSewa Configuration ESEWA_SECRET_KEY=8gBm/:&EnhH.1/q ESEWA_MERCHANT_CODE=EPAYTEST ESEWA_PAYMENT_CALLBACK_URL=http://localhost:5173/payment-result
Note: The above credentials are for eSewa's test environment. For production, use your actual merchant credentials.
-
Run migrations:
python manage.py migrate
-
Create superuser (optional):
python manage.py createsuperuser
-
Start development server:
python manage.py runserver
Backend will be available at
http://localhost:8000
-
Navigate to frontend directory:
cd frontend -
Install dependencies:
npm install
-
Create
.envfile in thefrontenddirectory:VITE_API_URL=http://localhost:8000
-
Start development server:
npm run dev
Frontend will be available at
http://localhost:5173
| Variable | Description | Example |
|---|---|---|
DJANGO_SECRET_KEY |
Django secret key | your-secret-key |
DEBUG |
Debug mode | True or False |
ESEWA_SECRET_KEY |
eSewa merchant secret key | 8gBm/:&EnhH.1/q (test) |
ESEWA_MERCHANT_CODE |
eSewa merchant/product code | EPAYTEST (test) |
ESEWA_PAYMENT_CALLBACK_URL |
Success/Failure callback URL | http://localhost:5173/payment-result |
| Variable | Description | Example |
|---|---|---|
VITE_API_URL |
Backend API base URL | http://localhost:8000 |
http://localhost:8000
Endpoint: POST /payments/esewa/
Description: Generates eSewa payment payload with signature for secure payment processing.
Request Body:
{
"amount": "1000",
"tax_amount": "0",
"product_service_charge": "0",
"product_delivery_charge": "0"
}Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
string | Yes | Payment amount |
tax_amount |
string | No | Tax amount (default: "0") |
product_service_charge |
string | No | Service charge (default: "0") |
product_delivery_charge |
string | No | Delivery charge (default: "0") |
Response:
{
"amount": "1000",
"tax_amount": "0",
"total_amount": "1000",
"transaction_uuid": "550e8400-e29b-41d4-a716-446655440000",
"product_code": "EPAYTEST",
"product_service_charge": "0",
"product_delivery_charge": "0",
"success_url": "http://localhost:5173/payment-result",
"failure_url": "http://localhost:5173/payment-result",
"signed_field_names": "total_amount,transaction_uuid,product_code",
"signature": "Gw2ax/N4W1q0TBqoXfwLhxuLOjDUxIzd08kLCHPn42s="
}Response Fields:
| Field | Type | Description |
|---|---|---|
amount |
string | Payment amount |
tax_amount |
string | Tax amount |
total_amount |
string | Total payment amount |
transaction_uuid |
string | Unique transaction identifier |
product_code |
string | eSewa merchant code |
product_service_charge |
string | Service charge |
product_delivery_charge |
string | Delivery charge |
success_url |
string | Success callback URL |
failure_url |
string | Failure callback URL |
signed_field_names |
string | Comma-separated field names used in signature |
signature |
string | HMAC-SHA256 signature |
cURL Example:
curl -X POST http://localhost:8000/payments/esewa/ \
-H "Content-Type: application/json" \
-d '{"amount": "1000"}'Endpoint: GET /payments/esewa/verify/
Description: Verifies payment status after eSewa callback.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
data |
string | Yes | Base64-encoded payment data from eSewa |
Request Example:
GET /payments/esewa/verify/?data=eyJ0cmFuc2FjdGlvbl91dWlkIjoiMTIzNDU2IiwicHJvZHVjdF9jb2RlIjoiRVBBWVRFU1QiLCJ0b3RhbF9hbW91bnQiOiIxMDAwIiwic3RhdHVzIjoiQ09NUExFVEUifQ==
Response:
{
"data": {
"transaction_uuid": "550e8400-e29b-41d4-a716-446655440000",
"product_code": "EPAYTEST",
"total_amount": "1000",
"status": "COMPLETE",
"transaction_id": "0008ACQ",
"ref_id": "000AXC"
}
}Response Fields:
| Field | Type | Description |
|---|---|---|
transaction_uuid |
string | Original transaction UUID |
product_code |
string | eSewa merchant code |
total_amount |
string | Transaction amount |
status |
string | Payment status (COMPLETE, FAILED, PENDING) |
transaction_id |
string | eSewa transaction ID |
ref_id |
string | eSewa reference ID |
Status Values:
COMPLETE- Payment successfulFAILED- Payment failedPENDING- Payment pending verification
Error Response:
{
"error": "No data received"
}cURL Example:
curl -X GET "http://localhost:8000/payments/esewa/verify/?data=eyJ0cmFuc2FjdGlvbl91dWlkIjoiMTIzNDU2In0="The API uses standard HTTP status codes:
| Status Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Missing or invalid parameters |
| 500 | Internal Server Error |
-
Open the application in your browser at
http://localhost:5173 -
Enter payment amount in the form (default: NPR 1000)
-
Click "Pay with eSewa" button
-
Complete payment on eSewa's payment page:
- For test environment, you can use demo credentials
- Test Success ID:
9806800001,9806800002,9806800003,9806800004,9806800005 - Password:
Nepal@123 - MPIN:
1234
-
View payment result - You'll be redirected to the payment result page showing:
- โ Success status with transaction details
- โ Failure status
- โณ Pending status
Located at src/components/payments/EsewaPaymentForm.jsx
import EsewaPaymentForm from './components/payments/EsewaPaymentForm';
function App() {
return <EsewaPaymentForm />;
}Located at src/pages/PaymentResult.jsx
Automatically handles the callback from eSewa and displays the payment status.
The paymentService.js provides two main functions:
import { generateEsewaPayment, EsewaPaymentVerify } from './services/paymentService';
// Initialize payment
const response = await generateEsewaPayment(amount);
// Verify payment
const result = await EsewaPaymentVerify({ data: encodedData });-
User Initiates Payment:
- User enters amount in the frontend form
- Frontend sends POST request to
/payments/esewa/
-
Backend Generates Payload:
- Generates unique transaction UUID
- Creates signing string from required fields
- Generates HMAC-SHA256 signature using merchant secret key
- Returns complete payment payload
-
Frontend Submits to eSewa:
- Creates a hidden HTML form with payload data
- Submits form to eSewa gateway (
https://rc-epay.esewa.com.np/api/epay/main/v2/form) - User is redirected to eSewa payment page
-
User Completes Payment:
- User logs into eSewa
- Reviews payment details
- Confirms payment
-
eSewa Redirects Back:
- eSewa redirects to callback URL with base64-encoded payment data
- Frontend extracts the
dataquery parameter
-
Payment Verification:
- Frontend sends GET request to
/payments/esewa/verify/with encoded data - Backend decodes and parses payment result
- Returns payment status and details
- Frontend sends GET request to
-
Display Result:
- Frontend displays success/failure/pending status
- Shows transaction details
The backend uses HMAC-SHA256 for signature generation:
# 1. Build signing string
signed_string = "total_amount=1000,transaction_uuid=550e8400-e29b-41d4-a716-446655440000,product_code=EPAYTEST"
# 2. Generate HMAC-SHA256 signature
signature = base64.b64encode(
hmac.new(
secret_key.encode('utf-8'),
signed_string.encode('utf-8'),
hashlib.sha256
).digest()
).decode('utf-8')Each payment gets a unique UUID v4 identifier:
import uuid
transaction_uuid = str(uuid.uuid4())
# Example: "550e8400-e29b-41d4-a716-446655440000"- HMAC Signature: All payments include HMAC-SHA256 signature for authentication
- Environment Variables: Sensitive credentials stored in
.envfiles (not in Git) - CORS Configuration: Controlled cross-origin requests
- UUID Transactions: Unique identifiers prevent replay attacks
- Base64 Encoding: Payment callback data is base64-encoded
- HTTPS: Use HTTPS in production for secure data transmission
- โ
Never commit
.envfiles to version control - โ Use strong, unique secret keys in production
- โ Implement rate limiting on payment endpoints
- โ Add logging and monitoring for payment transactions
- โ Validate and sanitize all user inputs
- โ Use HTTPS for all production endpoints
- โ Implement webhook signature verification
- โ Store transaction records in database for audit trail
- Set
DEBUG=Falsein Django settings - Use production eSewa credentials
- Configure proper CORS origins (remove
CORS_ALLOW_ALL_ORIGINS) - Set up HTTPS/SSL certificates
- Configure database backups
- Implement comprehensive logging
- Set up monitoring and alerts
- Add rate limiting middleware
- Configure allowed hosts in Django settings
- Use environment-specific configuration
For development and testing, use eSewa's test environment:
- Gateway URL:
https://rc-epay.esewa.com.np/api/epay/main/v2/form - Secret Key:
8gBm/:&EnhH.1/q - Merchant Code:
EPAYTEST
Test Login Credentials:
- ID:
9806800001,9806800002,9806800003,9806800004,9806800005 - Password:
Nepal@123 - MPIN:
1234
# Backend tests
cd backend
python manage.py test
# Frontend tests (if configured)
cd frontend
npm test-
CORS Errors:
- Ensure
django-cors-headersis installed and configured - Check
CORS_ALLOW_ALL_ORIGINSin settings.py
- Ensure
-
Signature Mismatch:
- Verify
ESEWA_SECRET_KEYmatches your merchant account - Check field order in
signed_field_names
- Verify
-
Payment Callback Not Working:
- Ensure callback URL is accessible
- Check URL format (must include protocol:
http://orhttps://)
-
Module Import Errors:
- Activate virtual environment
- Reinstall dependencies:
pip install -r requirements.txt
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
For issues and questions:
- Open an issue on GitHub
- Contact eSewa support for merchant account queries
- eSewa - Nepal's digital wallet
- Django REST Framework team
- React and Vite communities
Note: This is a development implementation. For production use, implement additional security measures, database storage for transactions, proper error handling, and comprehensive logging.