Getting Started
Welcome to Rupixpe Payment Gateway API documentation. This guide will help you integrate our payment services into your application.
Base URL
https://merchant.rupixpe.com/api/v1
Quick Setup
- Sign up for a merchant account at merchant.rupixpe.com
- Complete your KYC verification
- Get your API credentials from the Settings page
- Start integrating using the code examples below
Authentication
Rupixpe API uses API Key and Secret for authentication. Include these in your request headers.
Headers
| Header | Value | Description |
|---|---|---|
X-API-Key |
Your API Key | Your merchant API key from settings |
X-API-Secret |
Your API Secret | Your merchant API secret |
Content-Type |
application/json | Request content type |
Node.js Example
const axios = require('axios');
const API_KEY = 'your_api_key_here';
const API_SECRET = 'your_api_secret_here';
const BASE_URL = 'https://merchant.rupixpe.com/api/v1';
const apiClient = axios.create({
baseURL: BASE_URL,
headers: {
'X-API-Key': API_KEY,
'X-API-Secret': API_SECRET,
'Content-Type': 'application/json'
}
});
Payin API (Payment Collection)
Use Payin API to collect payments from your customers via UPI.
Create Payin Transaction
POST
/payin/create
Creates a new payment collection request.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
order_id |
string | Required | Your unique order identifier |
amount |
number | Required | Amount in INR (minimum: 10) |
customer_name |
string | Required | Customer's full name |
customer_email |
string | Required | Customer's email address |
customer_phone |
string | Required | Customer's phone number (10 digits) |
redirect_url |
string | Optional | URL to redirect after payment |
webhook_url |
string | Optional | Webhook URL for this transaction |
Node.js Example
async function createPayin() {
try {
const response = await apiClient.post('/payin/create', {
order_id: 'ORDER_' + Date.now(),
amount: 100.00,
customer_name: 'John Doe',
customer_email: 'john@example.com',
customer_phone: '9876543210',
redirect_url: 'https://yoursite.com/payment/success',
webhook_url: 'https://yoursite.com/webhook/payin'
});
console.log('Transaction ID:', response.data.data.transaction_id);
console.log('Payment URL:', response.data.data.payment_url);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
createPayin();
Success Response
{
"success": true,
"message": "Payin transaction created successfully",
"data": {
"transaction_id": "TXN_ABC123XYZ",
"order_id": "ORDER_1234567890",
"amount": 100.00,
"status": "pending",
"payment_url": "https://merchant.rupixpe.com/pay/TXN_ABC123XYZ",
"created_at": "2025-10-02T00:00:00.000Z"
}
}
Check Payin Status
GET
/payin/status/:transaction_id
Node.js Example
async function checkPayinStatus(transactionId) {
try {
const response = await apiClient.get(`/payin/status/${transactionId}`);
console.log('Status:', response.data.data.status);
console.log('Amount:', response.data.data.amount);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
checkPayinStatus('TXN_ABC123XYZ');
Success Response
{
"success": true,
"data": {
"transaction_id": "TXN_ABC123XYZ",
"order_id": "ORDER_1234567890",
"amount": 100.00,
"status": "success",
"upi_id": "john@paytm",
"utr": "123456789012",
"created_at": "2025-10-02T00:00:00.000Z",
"completed_at": "2025-10-02T00:01:30.000Z"
}
}
List Payin Transactions
GET
/payin/list
Query Parameters
| Parameter | Type | Description |
|---|---|---|
page |
number | Page number (default: 1) |
limit |
number | Items per page (default: 20, max: 100) |
status |
string | Filter by status: pending, success, failed |
from_date |
string | Start date (YYYY-MM-DD) |
to_date |
string | End date (YYYY-MM-DD) |
Node.js Example
async function listPayins() {
try {
const response = await apiClient.get('/payin/list', {
params: {
page: 1,
limit: 20,
status: 'success',
from_date: '2025-10-01',
to_date: '2025-10-02'
}
});
console.log('Total:', response.data.data.total);
console.log('Transactions:', response.data.data.transactions);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
listPayins();
Payout API (Money Transfer)
Use Payout API to transfer money to your customers or vendors via Bank Transfer (IMPS/NEFT/RTGS).
Initiate Payout
POST
/payout/initiate
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
reference_id |
string | Required | Your unique payout reference |
amount |
number | Required | Amount in INR (minimum: 100) |
beneficiary_name |
string | Required | Beneficiary's full name |
beneficiary_email |
string | Required | Beneficiary's email |
beneficiary_phone |
string | Required | Beneficiary's phone (10 digits) |
account_number |
string | Required | Beneficiary's bank account number |
ifsc_code |
string | Required | Beneficiary's bank IFSC code |
mode |
string | Optional | Transfer mode: 'IMPS', 'NEFT', or 'RTGS' (default: IMPS) |
purpose |
string | Optional | Purpose of transfer |
Node.js Example
async function initiatePayout() {
try {
const response = await apiClient.post('/payout/initiate', {
reference_id: 'PAYOUT_' + Date.now(),
amount: 1000.00,
beneficiary_name: 'Jane Doe',
beneficiary_email: 'jane@example.com',
beneficiary_phone: '9876543210',
account_number: '1234567890',
ifsc_code: 'HDFC0001234',
mode: 'IMPS',
purpose: 'Vendor payment'
});
console.log('Payout ID:', response.data.data.payout_id);
console.log('Status:', response.data.data.status);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
initiatePayout();
Success Response
{
"success": true,
"message": "Payout initiated successfully",
"data": {
"payout_id": "POUT_XYZ789ABC",
"reference_id": "PAYOUT_1234567890",
"amount": 500.00,
"status": "pending",
"created_at": "2025-10-02T00:00:00.000Z"
}
}
Check Payout Status
GET
/payout/status/:payout_id
Node.js Example
async function checkPayoutStatus(payoutId) {
try {
const response = await apiClient.get(`/payout/status/${payoutId}`);
console.log('Status:', response.data.data.status);
console.log('Amount:', response.data.data.amount);
console.log('UTR:', response.data.data.utr);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
checkPayoutStatus('POUT_XYZ789ABC');
List Payout Transactions
GET
/payout/list
Node.js Example
async function listPayouts() {
try {
const response = await apiClient.get('/payout/list', {
params: {
page: 1,
limit: 20,
status: 'success'
}
});
console.log('Total:', response.data.data.total);
console.log('Payouts:', response.data.data.payouts);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
listPayouts();
Check Wallet Balance
GET
/wallet/balance
Node.js Example
async function getWalletBalance() {
try {
const response = await apiClient.get('/wallet/balance');
console.log('Available Balance:', response.data.data.available_balance);
console.log('Pending Balance:', response.data.data.pending_balance);
return response.data;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
getWalletBalance();
Webhooks
Webhooks allow you to receive real-time notifications about transaction status changes.
Setup Webhook URLs
Configure your webhook URLs in the Merchant Dashboard Settings:
- Payin Webhook URL: Receives payment collection updates
- Payout Webhook URL: Receives payout status updates
Webhook Headers
All webhooks include these security headers:
| Header | Example Value | Description |
|---|---|---|
X-Webhook-Signature |
sha256=9e89bb8aed... |
HMAC-SHA256 signature for verification |
X-Webhook-Event |
payin.success |
Event type |
X-Webhook-ID |
TXN_ABC123XYZ |
Transaction/Payout ID |
X-Webhook-Timestamp |
2025-12-22T06:33:39.656Z |
ISO-8601 timestamp |
Content-Type |
application/json |
Body format |
User-Agent |
UPI-Middleware-Webhook/1.0 |
Webhook client identifier |
Payin Webhook Payload
{
"event": "payin.success",
"timestamp": "2025-12-22T06:33:39.656Z",
"data": {
"transaction_id": "TXN_ABC123XYZ",
"order_id": "ORDER_1234567890",
"amount": 100.00,
"fee": 2.00,
"net_amount": 98.00,
"currency": "INR",
"status": "success",
"utr": "123456789012",
"gateway_transaction_id": "GTW_TXN_123456",
"customer_name": "John Doe",
"customer_email": "john@example.com",
"customer_phone": "9876543210",
"created_at": "2025-12-22T06:30:00.000Z",
"updated_at": "2025-12-22T06:33:39.656Z"
}
}
Payout Webhook Payload
{
"event": "payout.success",
"timestamp": "2025-12-22T06:35:45.000Z",
"data": {
"payout_id": "POUT_XYZ789ABC",
"reference_id": "PAYOUT_1234567890",
"amount": 500.00,
"fee": 5.00,
"net_amount": 495.00,
"currency": "INR",
"status": "success",
"utr": "987654321098",
"beneficiary_name": "Jane Doe",
"beneficiary_account": "1234567890",
"beneficiary_ifsc": "HDFC0001234",
"transfer_mode": "IMPS",
"created_at": "2025-12-22T06:35:00.000Z",
"updated_at": "2025-12-22T06:35:45.000Z"
}
}
Webhook Events
| Event | Description |
|---|---|
payin.success |
Payment collection successful |
payin.failed |
Payment collection failed |
payin.pending |
Payment is being processed |
payin.cancelled |
Payment was cancelled |
payout.success |
Payout completed successfully |
payout.failed |
Payout failed |
payout.pending |
Payout is being processed |
Webhook Signature Verification
All webhooks include an X-Webhook-Signature header containing an HMAC-SHA256 signature. You must verify this signature to ensure the webhook is authentic.
How Signature Works
The signature is generated using HMAC-SHA256:
signature = HMAC-SHA256(JSON.stringify(payload), webhook_secret)
header_value = "sha256=" + signature
Get Your Webhook Secret
Your webhook secret is available in the Merchant Dashboard → Settings → Webhooks section. Keep it secure and never commit it to version control.
Node.js Webhook Handler with Verification
const express = require('express');
const crypto = require('crypto');
const app = express();
// IMPORTANT: Store webhook secret securely in environment variable
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; // Get from Merchant Dashboard
// Middleware to verify webhook signature
function verifyWebhookSignature(req, res, next) {
try {
// 1. Get signature from header
const receivedSignature = req.headers['x-webhook-signature'];
if (!receivedSignature || !receivedSignature.startsWith('sha256=')) {
console.error('Missing or invalid signature header');
return res.status(401).json({ error: 'Missing or invalid signature' });
}
// 2. Extract hex signature (remove 'sha256=' prefix)
const signature = receivedSignature.replace('sha256=', '');
// 3. Get raw request body (IMPORTANT: must be exact JSON string)
const rawBody = JSON.stringify(req.body);
// 4. Generate expected signature
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
// 5. Compare signatures using timing-safe comparison
const isValid = crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
if (!isValid) {
console.error('Signature verification failed');
return res.status(401).json({ error: 'Invalid signature' });
}
// 6. Verify timestamp to prevent replay attacks (optional but recommended)
const timestamp = req.headers['x-webhook-timestamp'];
const webhookAge = Date.now() - new Date(timestamp).getTime();
if (webhookAge > 5 * 60 * 1000) { // 5 minutes
console.error('Webhook too old:', webhookAge / 1000, 'seconds');
return res.status(401).json({ error: 'Webhook expired' });
}
// Signature is valid, proceed
next();
} catch (error) {
console.error('Signature verification error:', error);
return res.status(401).json({ error: 'Signature verification failed' });
}
}
// Use JSON parser
app.use(express.json());
// Payin webhook handler with signature verification
app.post('/webhook/payin', verifyWebhookSignature, (req, res) => {
const { event, data } = req.body;
console.log('✓ Verified Payin Webhook Received');
console.log('Event:', event);
console.log('Transaction ID:', data.transaction_id);
console.log('Status:', data.status);
console.log('Amount:', data.amount);
// Process the webhook based on event
switch(event) {
case 'payin.success':
// Update order status in your database
console.log('Payment successful!');
console.log('UTR:', data.utr);
// TODO: Mark order as paid in your database
// TODO: Send confirmation email to customer
break;
case 'payin.failed':
// Handle failed payment
console.log('Payment failed!');
// TODO: Update order status in your database
// TODO: Notify customer about failure
break;
case 'payin.pending':
// Payment is being processed
console.log('Payment pending...');
// TODO: Update order status to processing
break;
}
// Always respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});
// Payout webhook handler with signature verification
app.post('/webhook/payout', verifyWebhookSignature, (req, res) => {
const { event, data } = req.body;
console.log('✓ Verified Payout Webhook Received');
console.log('Event:', event);
console.log('Payout ID:', data.payout_id);
console.log('Status:', data.status);
console.log('Amount:', data.amount);
// Process the webhook based on event
switch(event) {
case 'payout.success':
// Update payout status in your database
console.log('Payout successful!');
console.log('UTR:', data.utr);
// TODO: Mark payout as completed in your database
break;
case 'payout.failed':
// Handle failed payout
console.log('Payout failed!');
// TODO: Update payout status and handle retry logic
break;
case 'payout.pending':
// Payout is being processed
console.log('Payout pending...');
// TODO: Update payout status to processing
break;
}
// Always respond with 200 to acknowledge receipt
res.status(200).json({ received: true });
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
console.log('Webhook secret configured:', WEBHOOK_SECRET ? 'Yes' : 'No');
});
Python (Flask) Webhook Handler
import hmac
import hashlib
import json
from flask import Flask, request, jsonify
from datetime import datetime, timedelta
app = Flask(__name__)
# IMPORTANT: Store webhook secret securely in environment variable
WEBHOOK_SECRET = "your_webhook_secret_here" # Get from Merchant Dashboard
def verify_webhook_signature(request):
"""Verify webhook signature"""
# 1. Get signature from header
received_signature = request.headers.get('X-Webhook-Signature')
if not received_signature or not received_signature.startswith('sha256='):
return False
# 2. Extract signature
signature = received_signature.replace('sha256=', '')
# 3. Get raw request body
raw_body = request.get_data(as_text=True)
# 4. Generate expected signature
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
raw_body.encode('utf-8'),
hashlib.sha256
).hexdigest()
# 5. Compare using timing-safe comparison
is_valid = hmac.compare_digest(signature, expected_signature)
# 6. Check timestamp (optional)
if is_valid:
timestamp_str = request.headers.get('X-Webhook-Timestamp')
if timestamp_str:
webhook_time = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
age = datetime.now() - webhook_time.replace(tzinfo=None)
if age > timedelta(minutes=5):
return False
return is_valid
@app.route('/webhook/payin', methods=['POST'])
def payin_webhook():
# Verify signature
if not verify_webhook_signature(request):
return jsonify({'error': 'Invalid signature'}), 401
# Parse webhook data
webhook_data = request.get_json()
event = webhook_data.get('event')
data = webhook_data.get('data')
print(f'✓ Verified Payin Webhook: {event}')
print(f'Transaction ID: {data.get("transaction_id")}')
print(f'Status: {data.get("status")}')
# Process based on event
if event == 'payin.success':
print(f'Payment successful! UTR: {data.get("utr")}')
# TODO: Update order status in your database
elif event == 'payin.failed':
print('Payment failed!')
# TODO: Handle failed payment
return jsonify({'received': True}), 200
@app.route('/webhook/payout', methods=['POST'])
def payout_webhook():
# Verify signature
if not verify_webhook_signature(request):
return jsonify({'error': 'Invalid signature'}), 401
# Parse webhook data
webhook_data = request.get_json()
event = webhook_data.get('event')
data = webhook_data.get('data')
print(f'✓ Verified Payout Webhook: {event}')
print(f'Payout ID: {data.get("payout_id")}')
# Process based on event
if event == 'payout.success':
print(f'Payout successful! UTR: {data.get("utr")}')
elif event == 'payout.failed':
print('Payout failed!')
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run(port=5000)
PHP Webhook Handler
<?php
// IMPORTANT: Store webhook secret securely
$webhookSecret = "your_webhook_secret_here"; // Get from Merchant Dashboard
function verifyWebhookSignature($payload, $receivedSignature, $secret) {
// 1. Check signature format
if (!$receivedSignature || strpos($receivedSignature, 'sha256=') !== 0) {
return false;
}
// 2. Extract signature
$signature = str_replace('sha256=', '', $receivedSignature);
// 3. Generate expected signature
$expectedSignature = hash_hmac('sha256', $payload, $secret);
// 4. Compare using timing-safe comparison
return hash_equals($expectedSignature, $signature);
}
// Get raw POST data
$rawPayload = file_get_contents('php://input');
// Get signature from header
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
// Verify signature
if (!verifyWebhookSignature($rawPayload, $receivedSignature, $webhookSecret)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
// Parse JSON payload
$webhookData = json_decode($rawPayload, true);
$event = $webhookData['event'];
$data = $webhookData['data'];
error_log("✓ Verified Webhook: $event");
// Process based on event
if ($event === 'payin.success') {
error_log("Payment successful! TXN: " . $data['transaction_id']);
// TODO: Update order status in your database
} elseif ($event === 'payin.failed') {
error_log("Payment failed!");
// TODO: Handle failed payment
}
// Always respond with 200
http_response_code(200);
echo json_encode(['received' => true]);
?>
Testing Webhook Signature
You can test signature verification using this Node.js script:
const crypto = require('crypto');
// Your webhook secret from Merchant Dashboard
const webhookSecret = "your_webhook_secret_here";
// Sample webhook payload
const payload = {
event: "payin.success",
timestamp: "2025-12-22T06:33:39.656Z",
data: {
transaction_id: "TXN_TEST123",
amount: 100.00,
status: "success"
}
};
// Generate signature
const payloadString = JSON.stringify(payload);
const signature = crypto.createHmac('sha256', webhookSecret)
.update(payloadString)
.digest('hex');
console.log('Payload:', payloadString);
console.log('Signature:', signature);
console.log('Header value:', `sha256=${signature}`);
Common Security Mistakes to Avoid
- ❌ Not verifying signature - Always verify the signature before processing
- ❌ Re-serializing JSON - Use the raw body, not JSON.stringify(req.body)
- ❌ String comparison - Use crypto.timingSafeEqual() to prevent timing attacks
- ❌ Hardcoding secret - Store webhook secret in environment variables
- ❌ Ignoring timestamp - Check webhook age to prevent replay attacks
- ❌ Not responding with 200 - Always return HTTP 200 to acknowledge receipt
Webhook Retry Policy
If your endpoint doesn't respond with HTTP 200, we will retry sending the webhook:
- Attempt 1: Immediate
- Attempt 2: 30 seconds later
- Attempt 3: 1 minute later
- Attempt 4: 3 minutes later
- Attempt 5: 5 minutes later
- Attempt 6: 10 minutes later
- Attempt 7: 20 minutes later
- Attempt 8: 30 minutes later
- Final Attempt: 1 hour later
Error Codes
Rupixpe API uses standard HTTP response codes and returns detailed error information.
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
200 |
Success | Request completed successfully |
400 |
Bad Request | Invalid parameters or missing required fields |
401 |
Unauthorized | Invalid or missing API credentials |
403 |
Forbidden | KYC not approved or insufficient permissions |
404 |
Not Found | Resource not found |
429 |
Too Many Requests | Rate limit exceeded |
500 |
Internal Server Error | Something went wrong on our end |
Error Response Format
{
"success": false,
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient wallet balance for payout"
}
}
Common Error Codes
| Error Code | Description |
|---|---|
INVALID_CREDENTIALS |
API Key or Secret is invalid |
KYC_NOT_APPROVED |
Complete KYC verification to use this API |
INSUFFICIENT_BALANCE |
Not enough balance in wallet |
INVALID_AMOUNT |
Amount below minimum or above maximum limit |
DUPLICATE_ORDER |
Order ID already exists |
INVALID_UPI |
Invalid UPI ID format |
RATE_LIMIT_EXCEEDED |
Too many requests, please slow down |
Complete Integration Example
Here's a complete Node.js example showing all major operations:
const axios = require('axios');
class RupixpeAPI {
constructor(apiKey, apiSecret) {
this.client = axios.create({
baseURL: 'https://merchant.rupixpe.com/api/v1',
headers: {
'X-API-Key': apiKey,
'X-API-Secret': apiSecret,
'Content-Type': 'application/json'
}
});
}
// Create Payin
async createPayin(orderData) {
try {
const response = await this.client.post('/payin/create', orderData);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error?.message || error.message);
}
}
// Check Payin Status
async getPayinStatus(transactionId) {
try {
const response = await this.client.get(`/payin/status/${transactionId}`);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error?.message || error.message);
}
}
// Initiate Payout
async initiatePayout(payoutData) {
try {
const response = await this.client.post('/payout/initiate', payoutData);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error?.message || error.message);
}
}
// Check Payout Status
async getPayoutStatus(payoutId) {
try {
const response = await this.client.get(`/payout/status/${payoutId}`);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error?.message || error.message);
}
}
// Get Wallet Balance
async getWalletBalance() {
try {
const response = await this.client.get('/wallet/balance');
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error?.message || error.message);
}
}
}
// Usage Example
async function main() {
const api = new RupixpeAPI('your_api_key', 'your_api_secret');
try {
// 1. Check Wallet Balance
console.log('Checking wallet balance...');
const balance = await api.getWalletBalance();
console.log('Available Balance:', balance.data.available_balance);
// 2. Create a Payin
console.log('\nCreating payin transaction...');
const payin = await api.createPayin({
order_id: 'ORDER_' + Date.now(),
amount: 100.00,
customer_name: 'John Doe',
customer_email: 'john@example.com',
customer_phone: '9876543210'
});
console.log('Transaction ID:', payin.data.transaction_id);
console.log('Payment URL:', payin.data.payment_url);
// 3. Check Payin Status
setTimeout(async () => {
console.log('\nChecking payin status...');
const status = await api.getPayinStatus(payin.data.transaction_id);
console.log('Status:', status.data.status);
// 4. If successful, initiate a payout
if (status.data.status === 'success') {
console.log('\nInitiating payout...');
const payout = await api.initiatePayout({
reference_id: 'PAYOUT_' + Date.now(),
amount: 50.00,
beneficiary_name: 'Jane Doe',
beneficiary_email: 'jane@example.com',
beneficiary_phone: '9876543210',
account_number: '1234567890',
ifsc_code: 'HDFC0001234',
mode: 'IMPS',
purpose: 'Refund'
});
console.log('Payout ID:', payout.data.payout_id);
}
}, 5000);
} catch (error) {
console.error('Error:', error.message);
}
}
main();
Support
Need help with integration? We're here to assist you!
Contact Information
Email: support@rupixpe.com
Merchant Dashboard: merchant.rupixpe.com
Response Time: Within 24 hours
Testing
We recommend testing all integrations in a controlled environment before going live:
- Use small amounts for initial testing
- Test all webhook events
- Verify error handling
- Test rate limits