Skip to content
All articles

Telegram shop bots for German SMBs: the anatomy of a chat store

Sep 16, 2026 · BaaS · 5 min

·By Dimitri Pisarev

A Telegram shop bot is a storefront with two surfaces: inline keyboards inside the chat and a Mini App web view, both backed by one HTTP service. Catalog, checkout, and order status live where the customer already is. No store review, no install step, and no card form for the simplest payment path.

For a German SMB the calculus differs from a startup's. Customers are walk-ins, regulars, and people from a twenty-kilometer radius. Nobody installs an app to buy 500 g of coffee. Plenty of them, though, open a chat app they already use every day.

What does a Telegram shop bot consist of?#

Three parts, and only the backend is complicated:

Chat surface. Reply keyboards navigate the catalog, inline keyboards carry product actions. Every button press arrives as a callback update at your webhook. callback_data is capped at 64 bytes, so the payload is an id like add:42, never the product itself.

Mini App surface. A web page (HTTPS only) opened inside Telegram, rendered with the chat's theme variables and authenticated by signed initData. This is where a cart with quantities beats a keyboard menu. The Bot API web-apps spec defines the whole contract, and it is short.

One backend. A webhook endpoint for chat events, a small HTTP API for the Mini App, and an orders table. In my own build this is grammY plus Hono plus SQLite: roughly a dozen endpoints in total, one deploy.

Note

A bot cannot message a user first. The customer presses Start once; after that the bot holds a chat thread that lasts years. Put the deep link (t.me/yourbot?start=...) on receipts, flyers, and the website so starting is one tap.

How do payments work without a card form?#

Two paths, both initiated from the bot:

Telegram Stars (currency XTR). The bot sends an invoice priced in Stars, Telegram collects, and the bot receives successful_payment as an update. Refunds are one API call (refundStarPayment). Subscriptions are built in via sendInvoice: subscription_period: 2592000 (30 days) turns any invoice into a monthly plan that renews without a cron job on your side.

A payment provider. Stripe and others integrate through Telegram Payments: the customer pays in euros by card, the provider handles PCI, money settles to your account directly. Physical goods usually want this path.

Stars trade convenience for a conversion spread: withdrawing them to fiat runs through Fragment at a rate below face value, so price in Stars deliberately. In my reference shop I anchor at 1 ⭐ = 2 cents and round in the customer's favor.

Why is this not just a worse app store?#

Compare honestly. An app store gives you a listing, updates through review, and a 15 to 30% cut on digital goods. A bot gives you a deploy, deep links that open a specific product (?startapp=hausmischung), inline sharing of product cards into any group chat, and no review between releases.

What the store has and the bot lacks: a browser for discovery, a payment sheet everyone knows, and independence from Telegram's policy decisions. A shop bot is the right shape when customers arrive through word of mouth, local search, or your website. It is the wrong shape for consumer acquisition at scale.

A working example you can poke#

I built and run one as a reference: @roestwerk_bot sells coffee with a Stars checkout, card payments in EUR through hosted Stripe Checkout (test mode), one-tap refunds from the order message itself, a monthly subscription, and a live order status that edits its own confirmation message from "bezahlt" to "wird geröstet" to "abholbereit". The interactive demo on the landing page walks through the same flow without opening Telegram.

The parts I would keep in any shop bot: the state machine that treats an order as paid, then roasting, then pickup; the refund button attached to the order message; and the subscription delegated to Telegram instead of a scheduler.

What breaks first in production#

  1. Unverified webhooks. Anyone who finds the URL can POST fake updates. Set secret_token when registering the webhook (1 to 256 chars) and check the X-Telegram-Bot-Api-Secret-Token header before parsing. Webhooks terminate only on ports 443, 80, 88, and 8443.
  2. Trusting the client. initDataUnsafe is attacker-controlled. Validate the initData HMAC on the server (the secret is the HMAC-SHA256 of your bot token keyed with the string "WebAppData") and check auth_date freshness while you are in there.
  3. Unanswered callbacks. Every callback_query needs an answerCallbackQuery call, or the customer's client shows a loading spinner for seconds. Answer first, process after.
  4. Duplicates. Telegram re-delivers updates after timeouts, so an order handler that is not idempotent sells the same coffee twice. Store the provider's delivery id, persist the order before you process it, and treat duplicates as a scheduling reality rather than an anomaly.
Gotcha

Product photos sent by URL are capped at 5 MB per image (10 MB if you upload the bytes yourself). Compress at build time instead of debugging "photo didn't send" reports from the catalog job.

Who should build one#

Shops whose catalog fits in a chat: pickup-based food and crafts, appointment businesses, subscription boxes. The chat thread doubles as the CRM. A Telegram user id is a stable customer key, order history is one query away, and notifications ride the same pipe when the shop needs to reach people elsewhere. The whole system is less code than a typical e-commerce plugin stack, and every part of it is one you wrote on purpose.