What I Learned Building a Real-Time Pulsa & Top-Up Backend with Node.js
This isn't a tutorial — just a story of how I ended up building a backend system to handle real-time prepaid top-ups (pulsa, internet data, utility tokens, etc.) using plain Node.js and WebSocket.
The system is live, used daily by users, and processes transactions through bank transfer detection + external API triggers. Here's how it evolved, and what I learned from the process.
🧹 Context
In my region, prepaid services like mobile data, electricity tokens (PLN), and even BPJS (national health insurance) payments are still very much in demand — and mostly processed manually.
I wanted to build something that can:
- Accept top-up requests from users
- Detect payment via bank mutation (MSSQL-based)
- Send that payment to a remote gateway
- Do all this in real-time with feedback to the frontend
💻 The Stack
Nothing fancy. I started with:
- Node.js — to handle backend logic
- WS (WebSocket) — for bi-directional real-time updates
- MSSQL — to query latest transfers/mutations
- Filesystem — queueing requests via JSON files
- Axios — to send top-up commands to the gateway
The queue system is very basic: JSON files are dropped into a req/
folder, then scanned every minute for matching payments.
🔄 Real-Time Looping
Each file contains a request like this:
{
"type": "MAXsi.ID TOPUP",
"kode": "IND10",
"tujuan": "0812700313",
"harga": 10313,
"nama": "Rizky",
"bank": "BRI",
"deviceId": "client-xyz"
}
Once a match is found in the bank mutation table (e.g. amount + name in keterangan
), the system triggers a request to an external API (in my case, OtomaX or a similar system).
The client is updated in real-time through the WebSocket connection.
🧠 Things That Surprised Me
- 🧵 WebSocket is underrated. For transactional systems, it's way better than polling.
- ⚖️ Parsing human-entered notes is unreliable. You'd be surprised how many ways someone can type "Rizky".
- ↺ Retry logic matters. Sometimes network flukes cause a miss, and the system needs to be idempotent.
- 📀 File-based queuing works, if you're disciplined. For low-traffic systems, it's dead simple and avoids DB overhead.
🧪 Bank Mutation Matching Logic
This is the trickiest part. I check:
amount >= harga
keterangan LIKE %nama%
- and
timestamp
is within ±45 mins
Even with that, I added safeguards like “processed files” tracker to avoid duplicate transactions.
✍️ Closing Thoughts
This system isn't perfect. But it's been running daily, reliably handling:
- Pulsa top-ups
- Token listrik (prepaid electricity)
- Bill payments like BPJS and PBB
I learned a lot from this — especially about simplifying automation. Sometimes, you don't need Kubernetes or Kafka. Just a folder, a WebSocket, and some console.log
.
If you're building anything in this space — fintech, automation, hybrid local-digital systems — I'd love to hear how you tackle these things.
Top comments (0)