Migrating a Telegram Store Bot to a Self-Hosted VPS — and Fixing a Payment System That Rejected Every Order
A live digital-goods store was running on Replit with a checkout that silently failed on every purchase. I moved it onto a hardened VPS, root-caused and fixed the payment-verification failure, completed a half-built anti-fraud system, and shipped new features and branded documentation — turning a fragile prototype into a production business that runs itself.
A live store that couldn’t take payments
The store sold digital goods through a Telegram bot, but it was running on Replit — convenient for a prototype, unsuitable for a real business moving money around the clock. There was no proper process management, no hardened database, and the whole thing leaned on a third-party runtime that could sleep, reset, or disappear at any moment.
The deeper issue was the checkout itself. Binance auto-verification had never actually worked. Every legitimate payment was silently rejected, so customers paid and received nothing until someone stepped in by hand — a slow, error-prone process that quietly bled away sales and trust. On top of that, the anti-fraud layer meant to protect deliveries was only half-built and effectively dead code, leaving the store wide open.
The brief was simple to state and hard to deliver: make it production-grade, fully self-hosted, and able to verify payments and deliver automatically — without ever getting defrauded.
End to end: infrastructure, data, fixes & features
Deployment & Infrastructure
Migrated the TypeScript/Node monorepo to Ubuntu 24.04 and provisioned the full stack — Node 20, PostgreSQL 16, and PM2 running under systemd so the bot starts automatically on boot. Then I hardened it: a non-root service user, a database bound to localhost only, SSH-key access, and locked-down secrets.
Data Migration
Recreated the schema and migrated all the real data — products, licence-key stock, images, orders and users. The tricky part was an ID collision between the old and new databases, which I solved with name-based remapping, fully idempotent imports, and backups at every step so nothing could be lost or double-counted.
Anti-Fraud Completion
The fraud logic depended on a “payer binding” that turned out to be dead code — it never ran. I implemented trust-on-first-use auto-delivery while preserving the guarantees that matter: cross-user uniqueness, per-user binding, and replay protection, so a payment can’t be reused or hijacked.
New Features
Built an animated chat experience — a storefront reveal and live verification progress bars — plus an in-Telegram, paginated sales dashboard. I also corrected the revenue accounting so it only recognises orders once payment is actually confirmed.
Tooling & Documentation
Set up a reproducible typecheck → build → deploy pipeline with pnpm and esbuild, so shipping a change is one predictable command. Delivered branded PDFs too: a client manual for day-to-day use and a developer maintenance guide for the future.
24/7 Reliability
PM2 and systemd keep the bot alive around the clock, restarting it automatically on a crash or server reboot. The store is now fully self-hosted with no dependency on any third-party runtime that could pause or pull the plug.
Why every valid payment was being rejected
This was the headline issue — and the most satisfying to crack. Binance auto-verification had never once worked in production, and the root cause turned out to be two bugs stacked on top of each other:
- It matched the wrong identifier. Verification compared the bot’s internal
transactionIdagainst Binance’s records instead of the customer’s actual Order ID — so it was hunting for something that could never match. - A silent number-vs-string mismatch. Even when the right values lined up, a type mismatch made every comparison fail quietly, with nothing logged — so valid payments were thrown out and no one could see why.
I fixed both, then hardened the flow with canonical-ID de-duplication so a single payment can never be redeemed twice. The result: payments now verify the moment they confirm, and delivery happens automatically — no manual checking, no lost sales.
From broken checkout to a store that runs itself
A payment flow that used to reject every order now verifies and auto-delivers in real time, with fraud protection fully intact. The store runs 24/7 on its own VPS — no third-party runtime, no manual babysitting — and the owner can see accurate sales and revenue right inside Telegram.
What it’s built with
Need something like this built — or fixed?
Telegram bots, payment integrations, server migrations, anti-fraud systems and automation. I take projects from broken or half-built to production-ready. Let’s talk.
Message me on Telegram