@bishaldahal/react-native-khalti-checkout
v0.2.2
Published
React Native/Expo SDK for Khalti Payment Gateway. Accept payments from Khalti, eBanking, mobile banking, and cards in Nepal.
Downloads
2,646
Maintainers
Readme
React Native Khalti Checkout
React Native/Expo SDK for Khalti Payment Gateway
Accept payments from Khalti wallet, eBanking, mobile banking, and cards in your Expo applications.
🚀 Quick Start • 📖 Usage • 💡 Examples • 🐛 Issues
🚀 Quick Start
Here's how to get Khalti payments working in your Expo app:
1. Installation
npx expo install @bishaldahal/react-native-khalti-checkout2. Build Development Client
⚠️ Important: This package requires native code and does not work with Expo Go.
# Create development build
eas build --profile development --platform android
# Or build locally
npx expo run:android3. Basic Usage
import KhaltiPaymentSdk from "@bishaldahal/react-native-khalti-checkout";
const handlePayment = async () => {
try {
const result = await KhaltiPaymentSdk.startPayment({
publicKey: "your_khalti_public_key",
pidx: "payment_id_from_backend", // Get this from your server
environment: "TEST", // Use "PROD" for production
});
console.log("Payment successful:", result);
} catch (error) {
console.error("Payment failed:", error);
}
};That's the basic setup. Jump to detailed setup or see complete example.
✨ Features
- 🔧 Expo Compatible - Fully tested with Expo SDK 52 & 53 (may work with others)
- 🚀 Easy Integration - Simple API with TypeScript support
- 🔒 Secure & Reliable - Built-in validation & error handling
- ⚡ Real-time Events - Listen to payment events instantly
- 🌍 Multi-environment - TEST and PROD environments
- 📱 Native Performance - Uses Khalti's official native SDKs
- 💾 Memory Safe - Automatic cleanup of event listeners
📋 Prerequisites
| Item | Requirement | Link | | ------------------ | --------------------------------- | ------------------------------------------------------------------------------------------ | | Platform | Expo SDK 52+ / React Native 0.72+ | Expo Docs | | OS Support | Android 5.0+ (API 21) & iOS 15.1+ | - | | Node.js | Version 16 or higher | Download | | Khalti Account | Merchant account with API keys | Test | Prod | | Development | Expo Development Build | Guide |
Environment Variables
| Variable | Description | Example | Required |
| ------------------- | -------------------------------- | ----------------------- | ------------ |
| KHALTI_PUBLIC_KEY | Public key from Khalti dashboard | test_public_key_xxxxx | ✅ |
| KHALTI_SECRET_KEY | Secret key (backend only) | test_secret_key_xxxxx | ✅ (Backend) |
Setup Guide
⚠️ Important: This SDK only works with Expo Development Builds (not Expo Go) and is fully tested with Expo SDK 52 & 53. Compatible with other versions but not guaranteed.
For New Projects
# Create new Expo project with latest SDK
npx create-expo-app@latest MyKhaltiApp --template blank-typescript
cd MyKhaltiApp
# Install Khalti SDK
npx expo install @bishaldahal/react-native-khalti-checkout
# Install development build dependencies
npx expo install expo-dev-client
npm install -g @expo/eas-cliFor Existing Projects
# Install Khalti SDK
npx expo install @bishaldahal/react-native-khalti-checkout
# Install development build dependencies
npx expo install expo-dev-client
npm install -g @expo/eas-cliConfigure Your Project
1. Update app.json/app.config.js:
{
"expo": {
"name": "Your App Name",
"slug": "your-app-slug",
"version": "1.0.0",
"platforms": ["android", "ios"],
"android": {
"package": "com.yourcompany.yourapp",
"versionCode": 1,
"compileSdkVersion": 34,
"targetSdkVersion": 34,
"minSdkVersion": 21
},
"ios": {
"bundleIdentifier": "com.yourcompany.yourapp"
},
"plugins": ["expo-dev-client"]
}
}2. Create development build:
# Setup EAS (first time only)
eas login
eas init
# Build for Android (recommended for testing)
eas build --profile development --platform android
# Install the APK on your device when build completes3. Start development:
# Start development server
npx expo start --dev-client
# Open on your device with the custom development buildUsage
Complete Payment Implementation
Here's a more complete example with event listeners and error handling:
import React, { useEffect, useState } from "react";
import { View, Button, Alert, Text } from "react-native";
import KhaltiPaymentSdk from "@bishaldahal/react-native-khalti-checkout";
export default function PaymentScreen() {
const [loading, setLoading] = useState(false);
useEffect(() => {
// Set up event listeners
const successSubscription = KhaltiPaymentSdk.onPaymentSuccess((payload) => {
console.log("Payment successful:", payload);
Alert.alert("Success", `Transaction ID: ${payload.txnId}`);
setLoading(false);
});
const errorSubscription = KhaltiPaymentSdk.onPaymentError((payload) => {
console.log("Payment failed:", payload);
Alert.alert(
"Payment Failed",
payload.error_description || "Unknown error"
);
setLoading(false);
});
const cancelSubscription = KhaltiPaymentSdk.onPaymentCancel((payload) => {
console.log("Payment cancelled:", payload);
Alert.alert("Payment Cancelled", "You cancelled the payment");
setLoading(false);
});
// Cleanup subscriptions
return () => {
successSubscription.remove();
errorSubscription.remove();
cancelSubscription.remove();
};
}, []);
// WARNING: This should be done from your backend in production
const createPaymentInBackend = async (amount: number) => {
// In production, make this API call from your backend server
const response = await fetch("YOUR_BACKEND_URL/create-khalti-payment", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
amount: amount,
orderId: `order-${Date.now()}`, // Unique order ID from the backend
customerInfo: {
name: "John Doe",
email: "[email protected]",
phone: "9800000000",
},
}),
});
const data = await response.json();
return data.pidx;
};
// Alternative: Frontend payment initiation (FOR DEMO/TESTING ONLY)
const createPaymentFromFrontend = async (amount: number) => {
try {
const response = await fetch(
"https://a.khalti.com/api/v2/epayment/initiate/",
{
method: "POST",
headers: {
Authorization: "key test_secret_key_your_secret_key_here", // NEVER do this in production
"Content-Type": "application/json",
},
body: JSON.stringify({
return_url: "https://example.com/payment/",
website_url: "https://example.com/",
amount: amount * 100, // Convert to paisa
purchase_order_id: `order-${Date.now()}`,
purchase_order_name: "Test Product",
customer_info: {
name: "John Doe",
email: "[email protected]",
phone: "9800000000",
},
}),
}
);
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || "Payment initialization failed");
}
return data.pidx;
} catch (error) {
throw new Error(`Failed to create payment: ${error.message}`);
}
};
const handlePayment = async () => {
setLoading(true);
try {
// Option 1: Get pidx from your backend (RECOMMENDED)
// const pidx = await createPaymentInBackend(100);
// Option 2: Frontend initiation (DEMO ONLY - NOT for production)
const pidx = await createPaymentFromFrontend(100);
// Start payment with Khalti SDK
await KhaltiPaymentSdk.startPayment({
publicKey: "test_public_key_your_key_here",
pidx: pidx,
environment: "TEST", // Use "PROD" for production
});
} catch (error) {
console.error("Payment error:", error);
Alert.alert("Error", error.message);
setLoading(false);
}
};
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
padding: 20,
}}
>
<Text style={{ fontSize: 18, marginBottom: 20 }}>
Khalti Payment Demo
</Text>
<Button
title={loading ? "Processing..." : "Pay NPR 100"}
onPress={handlePayment}
disabled={loading}
/>
<Text
style={{
marginTop: 20,
fontSize: 12,
color: "gray",
textAlign: "center",
}}
>
Note: This demo includes frontend payment initiation for testing.{"\n"}
In production, always create payments from your backend server.
</Text>
</View>
);
}Configuration Options
interface PaymentArgs {
publicKey: string; // Your Khalti public key
pidx: string; // Payment identifier from backend
environment?: "TEST" | "PROD"; // Default: 'TEST'
}Event Response Types
// Success response
interface PaymentSuccessPayload {
pidx: string;
txnId: string;
amount: number;
mobile: string;
status: string;
timestamp: number;
}
// Error response
interface PaymentErrorPayload {
error_key: string;
error_description: string;
timestamp: number;
}
// Cancel response
interface PaymentCancelPayload {
reason?: string;
timestamp: number;
}Testing
Test Credentials
For testing in the sandbox environment, use these:
| Field | Value | Notes |
| ------------- | ---------------------------- | ------------------------- |
| Khalti ID | 9800000000 to 9800000005 | Any of these test numbers |
| MPIN | 1111 | 4-digit PIN |
| OTP | 987654 | 6-digit verification code |
Common Issues & Solutions
"Module not found" error
You need to rebuild your development client after installing the package:
# Clear cache and rebuild
npx expo start --clear
eas build --profile development --platform android --clear-cachePayment not starting
Check these common issues:
- Verify your public key is correct
- Make sure the PIDX is valid and from your backend
- Check your network connection
- Validate the environment setting (TEST vs PROD)
Security Best Practices
✅ Do This
- Use public keys only in mobile apps
- Create payments from your backend server
- Verify payments server-side
- Use HTTPS for all API communications
- Validate payment status in your backend
❌ Don't Do This
- Never put secret keys in mobile apps
- Don't rely only on client-side payment verification
- Don't store sensitive payment data locally
📱 Platform Support
| Platform | Status | SDK Version | Notes | | ----------- | --------------- | ----------- | --------------------------- | | Android | Fully Supported | API 21+ | Works best for testing | | iOS | Fully Supported | iOS 15.1+ | Full native SDK integration |
Compatibility Matrix
| Expo SDK | React Native | Node.js | Status | | --------- | ------------ | ------- | ------------------- | | 52-53 | 0.72+ | 16+ | ✅ Fully Tested | | 49-51 | 0.70-0.71 | 16+ | ⚠️ May work | | < 49 | < 0.70 | < 16 | ❌ Not supported |
📖 API Reference
Core Methods
| Method | Parameters | Returns | Description |
| ---------------------------- | ------------- | -------------------------------- | -------------------------------- |
| startPayment(args) | PaymentArgs | Promise<PaymentSuccessPayload> | Initiates payment process |
| onPaymentSuccess(callback) | Function | Subscription | Listen for successful payments |
| onPaymentError(callback) | Function | Subscription | Listen for payment errors |
| onPaymentCancel(callback) | Function | Subscription | Listen for payment cancellations |
| closePayment() | None | Promise<void> | Closes current payment session |
Utility Methods
// Clean up all event listeners
KhaltiPaymentSdk.removeAllListeners();
// Check if SDK is ready
const isReady = KhaltiPaymentSdk.isReady();Example App
Check out the example application for a complete implementation with:
- 🔧 Complete configuration setup
- 💳 Payment flow implementation
- 🚨 Error handling patterns
- 🎨 UI integration examples
Run the Example
git clone https://github.com/bishaldahal/react-native-khalti-checkout.git
cd react-native-khalti-checkout/example
npm install
npx expo run:android🤝 Contributing
We welcome contributions!
How to contribute
# Fork and clone the repository
git clone https://github.com/your-username/react-native-khalti-checkout.git
cd react-native-khalti-checkout
npm install
# Run example app
cd example && npm install && npx expo run:androidGuidelines
- Follow existing code style
- Add tests for new features
- Update documentation when needed
- Test on real devices when possible
See Contributing Guide for more details.
📞 Support
Need help? Here are your options:
| Resource | Description | Link | | -------------------- | -------------------- | --------------------------------------------------------------------------------------------- | | 📚 Documentation | Official Khalti docs | docs.khalti.com | | 🐛 Bug Reports | Report issues | GitHub Issues | | 💬 Discussions | Community support | GitHub Discussions | | Email | Direct support | [email protected] |
Links
If you find this helpful, consider giving it a star on GitHub!
License
This project is licensed under the MIT License - see the LICENSE file for details.
📋 Third-Party Notices
This package uses the official Khalti Android SDK. See THIRD_PARTY_NOTICES.md for full license information.
🇳🇵 Made with ❤️ for the Nepalese Developer Community
Found this helpful? Give it a ⭐ on GitHub!
Happy Coding! 🚀
