Demo project

Telegram Mini App shop: TemplateForge

A storefront inside the messenger, Stars checkout, goods delivered by the bot.

storefront and bot development · Go · Next.js 15 · TypeScript · Tailwind · Zustand · Telegram Bot API · Telegram Stars

in progressStorefront not published, no live purchase run yet

10templates in four catalogue sections
5 screensthe buyer's path, catalogue to delivery
1 starcharged per order, refunded at once
4 checkson the order before the star is charged
no doublesa repeated payment never delivers twice
Demo first screen: Telegram Mini App shop: TemplateForge

The task

TemplateForge sells ready-made Notion templates. The shop already has a regular website; this project puts the same catalogue inside Telegram, so the buyer never leaves for a browser and never types a card number. The goods are digital - ten templates across four sections, delivered as a link. Payment runs on Telegram Stars, which needs neither a payment provider nor a bank contract, and that removes the main barrier for a solo seller.

This is a demo build: the company and the products are invented, the payments are demonstrations. Every invoice is issued for a single star regardless of the cart total, and the star comes back the moment the payment clears. The buyer is told so three times - in the bot’s greeting, in the invoice description, and in the message after the purchase.

The solution

Two parts: the storefront as a Telegram Mini App on Next.js with a static export, and a Go service holding both the bot and the http layer the storefront talks to.

  • The buying path stays inside the messenger: catalogue with a category filter and counters, product page with a screen gallery, contents and reviews, cart, payment method, delivery screen. Five screens; a sixth, the disclaimer page, is reachable from every one of them.
  • The bottom control is Telegram’s own MainButton - the same button adds to the cart, opens the cart and starts the payment. Outside Telegram the storefront draws its own button in the same place, so the pages still open in a plain browser, which is how the screens get captured and debugged.
  • The payment path is built like this: the storefront asks the bot for an invoice link, Telegram opens the invoice on top of the app, the bot re-checks the order before the charge, then sends the templates as a message and refunds the star immediately. If an owner chat is configured, a purchase card goes there.
  • Card payment in roubles is present on the screen but switched off, with an honest caption: available once the payment provider contract is signed. The interface promises nothing it cannot do.
  • While the storefront is unpublished, the /demo command covers the whole purchase mechanic: the bot assembles a demo cart, issues the invoice right in the chat, delivers the templates and returns the star. That path is covered by tests; it has not yet been run live for a real star.

Details that are easy to miss

  • The sign-in data a Mini App sends to the bot is verified by signature against the Telegram spec and has an expiry. That check is what protects the invoice endpoint: without it anyone could request an invoice under someone else’s name. Separately, CORS is limited to the storefront addresses in the config, so a foreign site in the buyer’s browser cannot read the response.
  • Prices are copied into the order the moment it is created, so editing the catalogue cannot rewrite an invoice that has already been issued. Before the charge the bot runs four checks - the order exists, it is not paid yet, the products are still there at the same price, the amount and currency match. Telegram allows ten seconds for that answer, so the checks are short and local.
  • The goods are never handed over twice for one order: a repeated payment is rejected by the pre-charge check, and a repeated payment notification runs into the charge id already on file, so the star is not refunded twice either.
  • Orders, payments and refunds are appended line by line to a journal file. A database is left out on purpose: there are three kinds of persistent state, the file survives a restart, reads by eye and needs no container in tests.
  • The bot token is printed nowhere - not in logs, not in error messages. Dedicated tests guard this, because the Telegram request URL carries the token in full and an unhandled transport error would drag it into the log.
  • The storefront and the bot speak Russian, and refusals shown to the buyer are whole Russian sentences - “the catalogue changed while your order was being placed” - while the technical detail stays in the log.
  • The demo is kept out of search: noindex in the metadata and in the response header, a separate disclaimer page linked from every screen. Delivery links point at the .demo domain, which is not delegated, so there is nothing to open behind them.
  • The seam between storefront and bot is testable without Telegram: one command starts the real http layer with a stub invoice issuer, and a mismatched path or field name shows up straight away.

The numbers

Ten templates in four sections, with filter counters that add up to the catalogue. The storefront is six screens: five on the buying path plus the disclaimer page. Every invoice is one star, four checks run on the order before the charge, and the journal holds three kinds of records: order, payment, refund.

What is left

The live run inside Telegram - buy for a star, receive the goods, watch the refund land in My Stars - has not happened yet: the mechanic is covered by tests, but nobody has made a real purchase. The storefront is unpublished, so there is no live demo link here: Telegram opens a Mini App over https only, and a public address is the next step. Card payment in roubles waits on the YooKassa contract, and the rouble invoice handling will be written once it is signed.