Internal system
Telegram Commerce Automation
A Telegram commerce system that coordinates product selection, CryptoBot and Wata card or SBP payments, signed webhooks and idempotent automatic fulfilment as one controlled transaction flow.
- Role
- Backend & Product Engineering
- Period
- 2022
- Categories
- BackendInfrastructure
- Stack
- Node.jsJavaScriptExpressTelegram Bot APISequelizeSQLiteMySQLUmzugCryptoBotWata · Card / SBPsystemd
Key metrics
- Gross order value
- ≈RUB 4.62M/year
- Completed-order value in the confirmed production bot; processed sales, not revenue.
- Exact source aggregate: RUB 4,616,463; ≈€51K at the fixed 90 RUB/EUR reference, not live FX.
- Completed orders
- 22,068/year
- Completed production orders in the same rolling 12-month window.
- Counted by unique order identity; retries are excluded.
- Unique customers
- 17,973/year
- Distinct production customer identities with at least one completed order in the same window.
- Aggregate only; no personal or payment data is published.
Overview
Telegram Commerce Automation turns a conversational purchase into a controlled transaction lifecycle: choose a supported product, confirm the recipient, create an invoice, verify the provider event, claim the order once and complete automatic fulfilment before reporting success.
This published project page is deliberately scoped to the confirmed tg-stars-bot service. It covers Telegram Stars, Premium, CryptoBot and Wata payments by bank card or SBP without exposing the closed repository, bot identity, provider credentials, customer records or details of other managed bots.
Challenge
A chat interface makes checkout feel simple, but the underlying system crosses several trust boundaries. Product configuration, exchange rates and provider availability can change independently, so an invoice must never be created from missing or invalid runtime state.
Payment callbacks are externally supplied and may be large, repeated, delayed or forged. Expensive signature work needs a bounded entry path, and a legitimate retry must not issue the same product twice.
A successful payment is not the same as a completed order. Provider state, fulfilment ownership, delivery attempts and user-visible status must stay consistent across transient failures, process restarts and operational maintenance.
Solution
The Telegram flow keeps product choice, supported quantities, recipient entry and order confirmation explicit. Checkout resolves the currently allowed methods—CryptoBot or Wata by bank card and SBP—and blocks a cryptocurrency invoice when its required rate is absent or invalid; Wata and automatic delivery remain unavailable until their required configuration exists.
Wata callbacks pass request-size and rate gates before RSA signature verification. Verified events are registered in a webhook journal under a unique deduplication key, then mapped onto persisted order state. Replayed events return safely without starting a second fulfilment attempt.
Paid orders are claimed with an expiring delivery lock before the fulfilment provider is called. A stable idempotency key follows the delivery request, the result is persisted before success notification, and bounded recovery jobs can resume eligible Wata or paid orders without treating an uncertain state as a new purchase.
Responsibilities
- Design the complete Telegram purchase flow for Stars, Premium, gifts and supported custom quantities.
- Integrate CryptoBot and Wata bank-card and SBP invoice creation while keeping rate and credential guards at the checkout boundary.
- Implement bounded Wata webhook ingestion, RSA signature verification and persisted event deduplication.
- Model order state, exclusive delivery claims, stable idempotency keys and bounded recovery paths for automatic fulfilment.
- Build customer order history and operational views without exposing provider internals in the normal purchase flow.
- Maintain Sequelize migrations, SQLite backup tooling and a MySQL import path for a future shared-database deployment.
- Operate the service through liveness and readiness checks, graceful shutdown and a reviewed manual production release workflow.
Architecture
Interface
Product and checkout flow
Services
Invoice and configuration guards
Signed webhook verification
Automatic fulfilment
Data
Idempotent order state
Migrations and backups
Automation
Telegram user
CryptoBot or Wata card / SBP
Infrastructure
Health and graceful runtime
Product choice, recipient and confirmation
Telegram user -> Product and checkout flow
Validated purchase intent
Product and checkout flow -> Invoice and configuration guards
Guarded invoice creation
Invoice and configuration guards -> CryptoBot or Wata card / SBP
External payment status event
CryptoBot or Wata card / SBP -> Signed webhook verification
Verified and deduplicated transition
Signed webhook verification -> Idempotent order state
Exclusive delivery claim and stable key
Idempotent order state -> Automatic fulfilment
Persisted result and user notification
Automatic fulfilment -> Product and checkout flow
Migrated state and recoverable snapshots
Idempotent order state -> Migrations and backups
Runtime configuration and readiness
Invoice and configuration guards -> Health and graceful runtime
Bounded HTTP lifecycle
Signed webhook verification -> Health and graceful runtime
Recovery jobs and graceful shutdown
Automatic fulfilment -> Health and graceful runtime
Technical decisions
Refuse an invoice when runtime pricing is unsafe
- Problem
- A configured catalog price is not enough when the provider invoice depends on a separate cryptocurrency rate that may be missing or stale.
- Decision
- Validate the relevant runtime rate and provider configuration before invoice creation, and remove unavailable methods from the user flow.
- Reason
- The system fails closed instead of presenting a payment request with an amount it cannot justify.
- Trade-off
- Checkout availability now depends on maintained production configuration and may intentionally narrow to another payment method.
Bound webhook work before cryptographic verification
- Problem
- Signature verification is necessary but relatively expensive, while an exposed webhook can receive oversized or repeated requests.
- Decision
- Apply request-size and rate gates before parsing and verifying the Wata RSA signature, without publishing the exact operational thresholds.
- Reason
- Untrusted traffic is constrained before it reaches the costly trust decision.
- Trade-off
- The limits need operational tuning so legitimate provider retries remain accepted.
Journal provider events before fulfilment
- Problem
- Payment providers retry callbacks, and processing the same valid event twice could trigger duplicate delivery.
- Decision
- Persist a provider-derived deduplication key in the webhook event journal before applying the event to the order.
- Reason
- A repeat becomes an observable no-op rather than a second transaction path.
- Trade-off
- The journal is now part of the payment-critical storage path and must remain available.
Separate paid state from delivery ownership
- Problem
- Multiple recovery paths or concurrent checks can observe the same paid order at the same time.
- Decision
- Require one worker to claim the order with an expiring lock and carry a stable idempotency key into fulfilment.
- Reason
- Payment confirmation can be retried independently while actual delivery remains exclusive and replay-safe.
- Trade-off
- Expired claims and uncertain provider results require careful recovery instead of an immediate blind retry.
Keep SQLite for one instance and prepare a shared-database path
- Problem
- SQLite WAL is practical for a single service process but does not provide the coordination model needed by horizontally distributed workers.
- Decision
- Use SQLite WAL for the current single-instance runtime, maintain migrations and backups, and provide a MySQL import path for shared storage.
- Reason
- The present deployment stays simple without hiding the architectural limit.
- Trade-off
- Horizontal scaling requires a deliberate database migration and operational change rather than adding more bot processes.
Media
Gallery
Outcomes
- The confirmed service now represents purchase, payment, webhook handling, fulfilment and user notification as one recoverable transaction lifecycle.
- Signature verification, webhook journaling, exclusive delivery claims and stable idempotency keys reduce the chance that retries become duplicate fulfilment.
- Storage migrations, backup tooling, health endpoints and graceful shutdown make operational work part of the system design and keep the confirmed service recoverable after deployment.
Verified highlights
- The current catalog supports Telegram Stars for self or as a gift, Telegram Premium and a guarded custom Stars quantity.
- Checkout integrates CryptoBot alongside Wata bank-card and SBP payments, and the cryptocurrency path blocks invoice creation when the required configured rate is not valid.
- Wata webhook requests are bounded before RSA signature verification; exact anti-abuse thresholds are not published.
- Provider events are stored in a webhook_events journal with a unique deduplication key.
- Only one worker can hold the delivery claim for an order, and fulfilment carries a stable idempotency key.
- SQLite runs in WAL mode for the single-instance service; migrations, SQLite backups and a MySQL import path are present.
- Separate liveness and readiness endpoints report process, database and Telegram polling state.
- Shutdown stops background recovery, Telegram polling, the HTTP server and database connections; production deployment remains manual rather than CI-driven.
Learnings
- In commerce automation, the difficult interface is the boundary between confirmed money and irreversible fulfilment—not the button that starts checkout.
- Idempotency needs several cooperating layers: provider-event deduplication, persisted order state, exclusive work ownership and a stable downstream delivery key.