Introduction
Connect IPS (Instant Payment System) is Nepal’s premier digital payment platform that enables seamless online transactions. This comprehensive guide will walk you through integrating Connect IPS with your Node.js application, covering everything from setup to production deployment.
What is Connect IPS?
Connect IPS is a real-time payment system that allows users to make instant payments using their bank accounts. It’s widely adopted in Nepal for e-commerce, bill payments, and digital transactions. The system uses digital signatures for security and provides a robust API for merchant integration.
Prerequisites
Before starting the integration, ensure you have:
- Node.js (v14 or higher)
- A Connect IPS merchant account
- Digital certificate (PFX file) from Connect IPS
- Basic knowledge of TypeScript/JavaScript
- Understanding of cryptographic signatures
Setting Up the Environment
First, install the required dependencies:
npm install crypto fs path pem nanoid axios node-rsa
npm install --save-dev @types/node @types/pem
Set up your environment variables inĀ .env
:
CONNECTIPS_MERCHANT_ID=your_merchant_id
CONNECTIPS_APP_ID=your_app_id
CONNECTIPS_APP_NAME=your_app_name
CONNECTIPS_PASSWORD=your_app_password
CONNECTIPS_CREDITOR_PASSWORD=your_certificate_password
CONNECTIPS_GATEWAY_URL=https://uat.connectips.com/connectipswebgw/loginpage // please confirm with connect ips support team
CONNECTIPS_CHECKTXN_URL=https://uat.connectips.com/connectipswebws/api/creditor/validatetxn //please confirm with connect ips support team
CONNECTIPS_SUCCESS_URL=https://yoursite.com/payment/success
CONNECTIPS_FAILURE_URL=https://yoursite.com/payment/failure
CONNECTIPS_PFX_PATH=./CREDITOR.pfx
Core Implementation
1. Digital Signature Generation
The heart of Connect IPS integration is generating secure digital signatures:
import * as crypto from 'crypto';
import * as pem from 'pem';
import { readFileSync } from 'fs';
class ConnectIpsService {
private readonly pkOptions = {
p12Password: process.env.CONNECTIPS_CREDITOR_PASSWORD, // this will provide you in your email , please contact connectips for this
};
async generatePrivateKey(pfx: Buffer): Promise<string> {
return new Promise((resolve, reject) => {
pem.readPkcs12(pfx, this.pkOptions, (err, cert) => {
if (cert && cert.key) {
resolve(cert.key);
} else {
reject(err || new Error('Failed to extract private key from PFX'));
}
});
});
}
async generateHash(data: string): Promise<string> {
try {
const pfx = this.getPFX();
const RSAKey = await this.generatePrivateKey(pfx);
// Convert to PKCS8 format
const NodeRSAConstructor = require('node-rsa');
const key = new NodeRSAConstructor(RSAKey);
const privateKey = key.exportKey('pkcs8');
// Create signature
const signer = crypto.createSign('sha256WithRSAEncryption');
signer.update(data);
const hash = signer.sign(privateKey, 'base64');
return hash;
} catch (error) {
throw new Error('Failed to generate digital signature');
}
}
getPFX(): Buffer {
const filePath = process.env.CONNECTIPS_PFX_PATH || './CREDITOR.pfx';
try {
return readFileSync(filePath);
} catch (err) {
throw new Error(`PFX file not found at: ${filePath}`);
}
}
async generateSignature(body: any) {
try {
// Create the message string exactly as specified in documentation
const message = this.objectToKeyValueString(body);
// Use the new generateHash method
const signature = await this.generateHash(message);
return signature;
} catch (error) {
console.error('Signature generation error:', error);
throw new HttpException(
'Failed to generate signature',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
objectToKeyValueString = (obj: any) => {
return Object.entries(obj)
.map(([key, value]) => `${key}=${value}`)
.join(',');
};
}
2. Creating Payment Orders
When a user initiates a payment, create a payment order:
async createPaymentOrder(orderId: string, amount: number) {
try {
// Convert amount to paisa (NPR smallest unit)
const amountInPaisa = amount * 100;
const transactionId = this.generateTransactionId(); // use nanoi or random generate transactionId but it should be be under the 20 characters and any payload should not exceed the 20 characters except token
const paymentData = {
MERCHANTID: process.env.CONNECTIPS_MERCHANT_ID,
APPID: process.env.CONNECTIPS_APP_ID,
APPNAME: process.env.CONNECTIPS_APP_NAME,
TXNID: transactionId, // should not exceed the 20 characters
TXNDATE: this.getCurrentDate(),
TXNCRNCY: 'NPR',
TXNAMT: amountInPaisa.toString(),
REFERENCEID: transactionId,
REMARKS: 'Order Payment', // should not exceed the 20 characters
PARTICULARS: 'E-commerce Purchase', // should not exceed the 20 characters
TOKEN: 'TOKEN', // Placeholder for signature
};
// Generate digital signature
const signature = await this.generateSignature(paymentData);
paymentData.TOKEN = signature;
return {
method: 'post',
gatewayUrl: process.env.CONNECTIPS_GATEWAY_URL,
keysValues: {
...paymentData,
successUrl: process.env.CONNECTIPS_SUCCESS_URL,
failureUrl: process.env.CONNECTIPS_FAILURE_URL,
},
};
} catch (error) {
throw new Error('Failed to create payment order');
}
}
generateTransactionId(): string {
return `TXN_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
getCurrentDate(): string {
const d = new Date();
return (
('0' + d.getDate()).slice(-2) +
'-' +
('0' + (d.getMonth() + 1)).slice(-2) +
'-' +
d.getFullYear()
);
}
3. Handling Payment Responses
After payment completion, Connect IPS redirects users back to your application:
async handlePaymentCallback(txnId: string) {
try {
// Verify payment status with Connect IPS
// for generating the signature the key should be in the uppercase
const checkData = {
MERCHANTID: process.env.CONNECTIPS_MERCHANT_ID,
APPID: process.env.CONNECTIPS_APP_ID,
REFERENCEID: txnId,
TXNAMT: await this.getTransactionAmount(txnId),
};
const signature = await this.generateSignature(checkData);
// for checking the status the payload should be in the camelcase
const payload = {
merchantId: process.env.CONNECTIPS_MERCHANT_ID,
appId: process.env.CONNECTIPS_APP_ID,
referenceId: txnId,
txnAmt: checkData.TXNAMT,
token: signature,
};
// Create basic auth header
const base64Cred = Buffer.from(
`${process.env.CONNECTIPS_APP_ID}:${process.env.CONNECTIPS_PASSWORD}`
).toString('base64');
const response = await axios.post(
process.env.CONNECTIPS_CHECKTXN_URL,
payload,
{
headers: {
Authorization: `Basic ${base64Cred}`,
'Content-Type': 'application/json',
},
}
);
return this.processPaymentStatus(response.data, txnId);
} catch (error) {
throw new Error('Payment verification failed');
}
}
processPaymentStatus(response: any, txnId: string) {
switch (response.status) {
case 'SUCCESS':
return this.updatePaymentStatus(txnId, 'completed', response);
case 'FAILED':
return this.updatePaymentStatus(txnId, 'failed', response);
case 'ERROR':
return this.updatePaymentStatus(txnId, 'cancelled', response);
default:
return this.updatePaymentStatus(txnId, 'unknown', response);
}
}
4. Express.js Route Implementation
Create routes to handle payment flow:
import express from 'express';
const router = express.Router();
// Initiate payment
router.post('/initiate', async (req, res) => {
try {
const { orderId, amount } = req.body;
const paymentData = await connectIpsService.createPaymentOrder(orderId, amount);
// Return payment form or redirect data
res.json(paymentData);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Handle payment success
router.get('/success', async (req, res) => {
try {
const { TXNID } = req.query;
const result = await connectIpsService.handlePaymentCallback(TXNID as string);
res.redirect(`/order-confirmation?status=success&txn=${TXNID}`);
} catch (error) {
res.redirect(`/order-confirmation?status=error&message=${error.message}`);
}
});
// Handle payment failure
router.get('/failure', async (req, res) => {
const { TXNID } = req.query;
res.redirect(`/order-confirmation?status=failed&txn=${TXNID}`);
});
export default router;
Frontend Integration
Create a payment form that submits to Connect IPS:
<!DOCTYPE html>
<html>
<head>
<title>Connect IPS Payment</title>
</head>
<body>
<form id="paymentForm" action="{{gatewayUrl}}" method="post">
<input type="hidden" name="MERCHANTID" value="{{MERCHANTID}}">
<input type="hidden" name="APPID" value="{{APPID}}">
<input type="hidden" name="APPNAME" value="{{APPNAME}}">
<input type="hidden" name="TXNID" value="{{TXNID}}">
<input type="hidden" name="TXNDATE" value="{{TXNDATE}}">
<input type="hidden" name="TXNCRNCY" value="{{TXNCRNCY}}">
<input type="hidden" name="TXNAMT" value="{{TXNAMT}}">
<input type="hidden" name="REFERENCEID" value="{{REFERENCEID}}">
<input type="hidden" name="REMARKS" value="{{REMARKS}}">
<input type="hidden" name="PARTICULARS" value="{{PARTICULARS}}">
<input type="hidden" name="TOKEN" value="{{TOKEN}}">
<input type="hidden" name="successUrl" value="{{successUrl}}">
<input type="hidden" name="failureUrl" value="{{failureUrl}}">
<button type="submit">Proceed to Payment</button>
</form>
</body>
</html>
Security Best Practices
- Certificate Management: Store PFX files securely and never commit them to version control
- Environment Variables: Use secure environment variable management
- Input Validation: Always validate and sanitize input data
- HTTPS Only: Ensure all communication uses HTTPS
- Signature Verification: Always verify payment responses with Connect IPS
Testing and Production Deployment
Testing
- Use Connect IPS sandbox environment for testing
- Implement comprehensive unit tests for signature generation
- Test all payment scenarios: success, failure, and cancellation
Production Deployment
- Use production certificates and URLs
- Implement proper logging and monitoring
- Set up webhook endpoints for payment notifications
- Implement retry mechanisms for network failures
Conclusion
Integrating Connect IPS with Node.js requires careful attention to security, especially digital signature generation. This implementation provides a robust foundation for processing payments in Nepalese e-commerce applications. Remember to thoroughly test your integration and follow Connect IPS guidelines for production deployment.
The key success factors are proper certificate management, accurate signature generation, and comprehensive error handling. With this implementation, you can confidently process payments through Connect IPS while maintaining security and reliability.
its fine need some colors