npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@babuperumana/upipg-new

v1.0.0

Published

Full-featured UPI payment gateway with automated BharatPe verification, SQLite persistence, branded QR codes, and payer VPA capture

Readme

@babuperumana/upipg-new

Full-featured UPI payment gateway for Node.js with automated BharatPe verification, SQLite persistence, branded QR codes, and payer VPA capture. No webhooks or public servers needed.

Node.js License

Features

  • Automated payment verification — Background polls BharatPe every 5 seconds; no webhooks or public IP required
  • Payer VPA capture — Automatically fetches the payer's UPI ID (person@okaxis) via BharatPe's transaction detail endpoint
  • Micro-amount collision avoidance — Unique fractional amounts (₹100.00 → ₹100.03) so multiple customers can pay simultaneously
  • Branded QR codes — Generates high-resolution PNG QR cards via the upi://pay deep-link URI
  • SQLite persistence — All merchants, payments, events, and polling logs stored locally
  • Event-driven architecture — Listen for success, expired, and credentials_expired events
  • REST API + Dashboard — Full Express API with a built-in dark-mode dashboard and mobile-friendly payment status pages
  • SSE live events — Real-time payment status stream via Server-Sent Events
  • Credential hot-reload — Update BharatPe API token/cookie without restarting
  • Multi-merchant — Register multiple merchants; each polls independently

How It Works

Customer opens payment link
         │
         ▼
Server creates order + generates QR / UPI link
         │
         ▼
Customer pays via any UPI app (GPay, PhonePe, BHIM, PayTM...)
         │
         ▼
BharatPe records the transaction on merchant's account
         │
         ▼
Background poller (every 5s) fetches recent QR transactions
         │
         ▼
Matches by amount + time window
         │
         ▼
Fetches transaction detail → captures payer VPA, UTR, payer name, handle
         │
         ▼
Updates SQLite DB → emits `success` event → payment page auto-refreshes

Installation

npm install @babuperumana/upipg-new

Prerequisites

  1. A BharatPe merchant account with QR payments enabled
  2. Your BharatPe API token and cookie (obtain via browser DevTools → Network tab on the BharatPe merchant dashboard)

Quick Start

1. Set up environment

Copy .env.example to .env (optional — defaults work for local use):

PORT=3000
HOST=0.0.0.0
DB_PATH=./data/upi-gateway.db

2. Register a merchant

node scripts/setup.js

Or with command-line flags:

node scripts/setup.js \
  --name "Kaippulli Temple" \
  --upi "BHARATPE.8S0S0J3C6E51057@fbpe" \
  --mid "49354135" \
  --token "4dac28e239f3467fa3e96305f1adeb60" \
  --cookie "eyJpdiI6..." \
  --poll 5000 \
  --timeout 300

3. Start the server

npm start

Server runs at http://localhost:3000

4. Create a payment

curl -X POST http://localhost:3000/payments \
  -H "Content-Type: application/json" \
  -d '{"merchant_id": 1, "amount": 100}'

Response:

{
  "order_id": "ORD_1786177314232_886",
  "session_amount": 100,
  "status": "PENDING",
  "qr_code_url": "http://localhost:3000/qr/ORD_1786177314232_886",
  "upi_uri": "upi://pay?pa=...&am=100.00&tn=ORD_1786177314232_886",
  "status_url": "http://localhost:3000/pay/ORD_1786177314232_886"
}

5. Share with payer

Share any of these with the payer:

  • UPI deep-link: upi://pay?pa=... (opens their UPI app directly)
  • QR image: http://localhost:3000/qr/:orderId
  • Status page: http://localhost:3000/pay/:orderId (mobile-friendly, auto-refreshes)

The poller will auto-detect the payment within 5–10 seconds and capture VPA + UTR.

API Reference

Health

GET /health

Returns server status, active merchant count, and payment counts by status.

Merchants

GET    /merchants                        List all active merchants
GET    /merchants/:id                    Get merchant details (credentials excluded)
POST   /merchants                        Register new merchant
PUT    /merchants/:id                    Update merchant
DELETE /merchants/:id                    Deactivate merchant
GET    /merchants/:id/credentials/check  Verify BharatPe credentials
POST   /merchants/:id/credentials/update Update credentials live
POST   /merchants/:id/poll               Run one verification pass manually
GET    /merchants/:id/poll-logs          Recent polling logs

Payments

POST   /payments                         Create payment order
GET    /payments/:orderId                Get payment details + events
GET    /payments                         List all payments (filterable)
GET    /merchants/:merchantId/payments   Merchant payments (paginated)
POST   /payments/:orderId/enrich         Backfill payer VPA for old payments

QR & UPI

GET /qr/:orderId                         QR code PNG image
GET /payments/:orderId/qr                QR code PNG (download)
GET /payments/:orderId/qr/uri            UPI deep-link URI

Payment Status Page

GET /pay/:orderId                        Mobile-friendly payment page (auto-refreshes)

Events

GET /events/:orderId                     Event timeline for a payment
GET /events/stream                       SSE live event stream

Gateway

GET /gateway/status                      All registered gateway statuses

Payment Object

{
  "order_id": "ORD_1786177314232_886",
  "base_amount": 100,
  "session_amount": 100,
  "status": "SUCCESS",
  "utr": "658078651930",
  "payer_vpa": "perumanababu-1@okaxis",
  "payer_name": "Babu Perumana",
  "payer_handle": "Google Pay",
  "metadata": {"purpose": "donation"},
  "created_at": "2026-08-08 08:21:54",
  "completed_at": "2026-08-08 08:25:12",
  "merchant": {
    "name": "Kaippulli Temple",
    "upi_id": "BHARATPE.8S0S0J3C6E51057@fbpe"
  }
}

Payment Status Values

| Status | Description | |---|---| | PENDING | Awaiting payment | | SUCCESS | Payment verified by BharatPe | | FAILURE | Payment failed or expired | | EXPIRED | Session timed out (default 5 minutes) |

Events

Every state change is logged:

[
  {
    "event_type": "created",
    "payload": {"orderId": "...", "baseAmount": 100, "sessionAmount": 100},
    "created_at": "2026-08-08 08:21:54"
  },
  {
    "event_type": "success",
    "payload": {"utr": "658078651930", "payerVpa": "perumanababu-1@okaxis", "payerName": "Babu Perumana", "payerHandle": "Google Pay"},
    "created_at": "2026-08-08 08:25:12"
  }
]

Programmatic Usage

const { paymentService, qr, db } = require('@babuperumana/upipg-new');

// Create a payment
const session = await paymentService.createPayment(1, {
  amount: 100,
  metadata: { customerId: 'CUST_001' }
});

// Listen for events
paymentService.on('payment:success', ({ orderId, payerVpa }) => {
  console.log(`Payment ${orderId} from ${payerVpa}`);
});

paymentService.on('payment:expired', ({ orderId }) => {
  console.log(`Payment ${orderId} expired`);
});

paymentService.on('credentials:expired', ({ merchantId }) => {
  console.log(`Merchant ${merchantId} credentials expired`);
});

// Generate QR
const buffer = await qr.generateQR('merchant@bank', 'My Store', 100, 'ORD_123');
const uri = qr.buildUpiUri('merchant@bank', 'My Store', 100, 'ORD_123');

// Direct DB access
const payment = db.getPaymentByOrderId('ORD_123');

Configuration

Merchant Config

| Field | Required | Description | |---|---|---| | name | Yes | Merchant display name | | upi_id | Yes | Merchant UPI ID | | merchant_id | Yes | BharatPe merchant ID | | api_token | Yes | BharatPe API session token | | api_cookie | Yes | BharatPe cookie string | | bharatpe_api | No | Custom BharatPe API endpoint | | user_agent | No | Custom User-Agent header | | poll_interval | No | Polling interval in ms (default: 5000) | | timeout | No | Session timeout in seconds (default: 300) | | min_amount | No | Minimum payment amount in INR (default: 1.0) | | max_amount | No | Maximum payment amount in INR (default: 50000.0) |

Environment Variables

| Variable | Default | Description | |---|---|---| | PORT | 3000 | Server port | | HOST | 0.0.0.0 | Server bind address | | DB_PATH | ./data/upi-gateway.db | SQLite database path |

Database Schema

merchants
  ├── id, name, upi_id, merchant_id
  ├── api_token, api_cookie, bharatpe_api
  ├── poll_interval, timeout, min_amount, max_amount
  ├── is_active, created_at, updated_at

payments
  ├── id, order_id (unique), merchant_id
  ├── amount, session_amount, status
  ├── utr, payer_vpa, payer_name, payer_handle
  ├── metadata, created_at, completed_at

events
  ├── id, payment_id, event_type, payload, created_at

polling_log
  ├── id, merchant_id, status
  ├── transactions_checked, matched, error, created_at

Deployment

With PM2 (recommended for production)

npm install -g pm2
pm2 start src/server.js --name upi-gateway
pm2 save
pm2 startup

With Docker

FROM node:20-alpine
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY src/ ./src/
COPY scripts/ ./scripts/
COPY .env.example ./.env
EXPOSE 3000
CMD ["npm", "start"]

Environment notes

  • Set HOST=0.0.0.0 to accept external connections
  • Set PORT to your desired port
  • The SQLite DB file is created automatically at DB_PATH
  • For production, use a process manager like PM2 or systemd

How BharatPe Credentials Are Obtained

  1. Log into your BharatPe merchant dashboard
  2. Open Browser DevTools → Network
  3. Navigate to the transactions page
  4. Find any API request to payments-tesseract.bharatpe.in
  5. Copy the token and Cookie headers

These credentials are stored in the SQLite database and used for all polling.

Architecture

src/
  index.js          → Public package entry point
  server.js         → Express REST API + dashboard + SSE
  paymentService.js → UpiPG wrapper, event handlers, VPA enrichment
  database.js       → SQLite layer (better-sqlite3)
  qrHelper.js       → QR code & UPI deep-link generation
scripts/
  setup.js          → Interactive merchant registration CLI

License

MIT