upi-auto-capture
v0.2.0
Published
Minimal BharatPe UPI payment auto-capture — no database, in-memory only
Maintainers
Readme
upi-auto-capture
Minimal BharatPe UPI payment auto-capture — no database, no magic, just works.
Install
npm install upi-auto-captureQuick start
const express = require('express');
const { UpiPayment, buildRouter } = require('upi-auto-capture');
const upi = new UpiPayment({
upiId: 'BHARATPE.xxxx@fbpe',
merchantId: '49354135',
token: '<BharatPe API token>',
cookie: '<BharatPe API cookie>',
});
const app = express();
app.use(express.json());
// Mount the payment routes
app.use('/pay', buildRouter(upi));
app.listen;API
POST /pay/create
Create a payment session.
curl -X POST http://localhost:3000/pay/create \
-H "Content-Type: application/json" \
-d '{"orderId":"ORD-001","amount":10.00}'Response:
{
"status": "OK",
"orderId": "ORD-001",
"payToken": "a1b2c3d4",
"qrCodeUrl": "data:image/png;base64,...",
"upiDeepLink": "upi://pay?pa=...&am=10.00&pn=Pay&tn=ORD-001",
"expiresAt": 1700000000000,
"sessionAmount": 10.00
}GET /pay/status/:orderId or POST /pay/status
Check payment status.
curl http://localhost:3000/pay/status/ORD-001Response (pending):
{ "status": "PENDING" }Response (captured):
{
"status": "SUCCESS",
"utr": "123456789012",
"payerVpa": "customer@okaxis",
"payerName": "John Doe",
"payerHandle": "Google Pay",
"amount": 10.00
}Response (expired):
{ "status": "FAILURE" }upi.checkPayment(orderId) (programmatic)
const result = await upi.checkPayment('ORD-001');
if (result.status === 'SUCCESS') {
console.log('UTR:', result.utr);
console.log('Payer VPA:', result.payerVpa); // e.g. "customer@okaxis"
console.log('Payer Name:', result.payerName);
console.log('App Used:', result.payerHandle); // "Google Pay", "PhonePe", etc.
}upi.findPayment(amount, windowMinutes) (manual reconciliation)
Look up a payment by amount — useful for enriching old sessions or finding payments after a server restart.
const result = await upi.findPayment(10.03, 15);
// { found: true, utr: '...', payerVpa: 'customer@okaxis', payerName: 'John Doe', payerHandle: 'Google Pay', amount: 10.03 }How payerVpa works
The BharatPe PAYMENT_QR transaction list endpoint does not include the payer's UPI VPA. This package fetches it automatically using a two-step process:
- List —
GET /api/v1/merchant/transactions?module=PAYMENT_QR&merchantId=...— finds the matching transaction by amount - Detail —
GET /api/v1/merchant/transactions/{id}?module=PAYMENT_QR&merchantId=...— returns full details includingpayerVpa
The payerVpa enrichment happens automatically in checkPayment() and findPayment() — no extra code needed.
How it works
- Unique amount algorithm — each payment gets a slightly different amount (base + 0.01 to base + 0.99) so QR codes don't collide.
- In-memory sessions — 5-minute TTL, auto-expire. No database needed.
- BharatPe polling — the status endpoint queries BharatPe's transaction API and matches by amount (no stale date filters).
- payerVpa enrichment — after matching a transaction, a second API call fetches the payer's UPI ID from the transaction detail endpoint.
Options
const upi = new UpiPayment({
upiId: 'BHARATPE.xxx@fbpe',
merchantId: '49354135',
token: '...',
cookie: '...',
ttl: 300, // session TTL in seconds (default: 300)
});
// Customize route prefix
app.use('/payment', buildRouter(upi));Response fields
| Field | Description |
|-------|-------------|
| status | PENDING, SUCCESS, or FAILURE |
| utr | UPI transaction reference number |
| payerVpa | Payer's UPI ID (e.g. user@okaxis) |
| payerName | Payer's registered name on UPI |
| payerHandle | UPI app used (Google Pay, PhonePe, BHIM, etc.) |
| amount | Amount paid in INR |
Requirements
- Node.js >= 18
- BharatPe merchant account with API access
License
MIT
