Skip to main content

Mini App configuration

A connected Mini App needs settings in three places: the Mini App's Vite build, the API, and Telegram itself (BotFather and the bot webhook). Secrets live only in the API. Every VITE_ value is compiled into the JavaScript bundle and is public.

:::danger Never put secrets in VITE_ variables Bot tokens, webhook secrets, the assertion private key and Supabase keys are read only by the API. Anything prefixed with VITE_ ends up in the browser. :::

Client Mini App​

File: apps/client_tg_app/.env.local (start from .env.example).

# Read only by the local bot.py launcher, never by the Vite build.
TELEGRAM_BOT_TOKEN=
VITE_API_URL=http://127.0.0.1:3000
VITE_CHANNEL_AUTH_APP=client
VariableRead byRequiredBehavior
VITE_API_URLVite buildFor a production buildPublic API origin for sign-in (/auth/*) and business requests. If empty, a development build uses http://127.0.0.1:3000, and a production build calls paths on its own origin. Set it at build time; changing it later does not change a built bundle
VITE_CHANNEL_AUTH_APPVite buildNoChannel-auth app ID sent when creating an exchange context. Defaults to client. Must be a key in the API's CHANNEL_AUTH_TELEGRAM_APPS_JSON whose role is client
TELEGRAM_BOT_TOKENbot.py onlyFor bot.pyToken of a test client bot used by the polling launcher. Not used by the app or the API

Professional (master) Mini App​

File: apps/master_tg_app/.env (start from .env.example).

# Read only by bot/bot.py.
BOT_TOKEN=
WEBAPP_URL=https://your-public-https-host
VITE_API_URL=
VITE_CHANNEL_AUTH_APP=professional
VITE_SUPPORT_CHAT_URL=
VariableRead byRequiredBehavior
VITE_API_URLVite buildNoAPI origin. Leave empty to call the page's own origin; the dev and preview servers then proxy /auth and /professional to VITE_API_PROXY_TARGET, so a single tunnel serves both the app and the API. Set it for a production build hosted apart from the API
VITE_CHANNEL_AUTH_APPVite buildNoChannel-auth app ID. Defaults to professional. Must be a key in CHANNEL_AUTH_TELEGRAM_APPS_JSON whose role is professional
VITE_SUPPORT_CHAT_URLVite buildNoTelegram link opened by the support entry in the More screen. When empty, that entry does nothing
VITE_CLIENT_WEB_PREVIEW_URLVite buildNoOrigin of a running client web app used by the onboarding test-booking preview. Without it, the normal Bookygram schedule URL is used. Not listed in .env.example
BOT_TOKENbot/bot.py onlyFor the launcherToken of a test professional bot used by the polling launcher
WEBAPP_URLbot/bot.py onlyFor the launcherPublic HTTPS URL the bot's menu button and /start button open. run_preview.py overrides it with its tunnel domain

Process environment read by vite.config.ts, not by the bundle:

VariableDefaultBehavior
VITE_API_PROXY_TARGEThttp://127.0.0.1:3000Where the dev and preview servers proxy /auth and /professional
BOOKYGRAM_PREVIEWunsetSet to 1 by run_preview.py. The build then emits preview-version.json and a script that reloads open pages after a rebuild. Never set it for a real build

API settings the Mini Apps depend on​

Set these in apps/api/.env (development) or the deployment's secret store. The full validation rules are in Environment variables.

VariableRequiredWhy the Mini Apps need it
CHANNEL_AUTH_ISSUER_URLProduction; enables the /auth/* routes everywhereThe API's own public HTTPS origin, used as the OIDC issuer. Without it the Mini Apps cannot sign in
CHANNEL_AUTH_TELEGRAM_APPS_JSONProductionMaps each app ID to its bot: {"client":{"role":"client","botToken":"…","webhookSecret":"…"},"professional":{"role":"professional",…}}. The bot token verifies launch data; the webhook secret authenticates bot updates
CHANNEL_AUTH_TELEGRAM_MAX_AGE_SECONDSNo (default 3600)Oldest launch data accepted at sign-in
CHANNEL_AUTH_ASSERTION_PRIVATE_KEYWhen enabledRSA (≥ 2048-bit) PKCS#8 PEM that signs the identity assertion
CHANNEL_AUTH_ASSERTION_RETIRED_PUBLIC_KEYS_JSONNoOld public keys still published during a rotation
CHANNEL_AUTH_ASSERTION_AUDIENCEWhen enabledClient ID of the custom OIDC provider in Supabase Auth
CHANNEL_AUTH_SUPABASE_PROVIDERWhen enabledProvider ID in Supabase Auth, such as custom:bookygram-channels
SUPABASE_URLYesSupabase project; the API calls its token, refresh and logout endpoints
SUPABASE_PUBLISHABLE_KEYWhen enabledSent as apikey to Supabase Auth. Never the secret key
CLIENT_APP_ORIGINProductionHTTPS origin hosting the client Mini App. Allowed by CORS in production
PROFESSIONAL_APP_ORIGINProductionHTTPS origin hosting the professional Mini App. Allowed by CORS in production
CORS_ORIGINProductionWebsite origin, allowed alongside the two Mini App origins
CLIENT_MANAGEMENT_LINK_KEYS_JSONProductionVersion-to-secret map for personal booking management links that the client app claims

Outside production the API allows any CORS origin, so the app origins are optional during development. App origins must be exact HTTPS origins with no path or trailing slash.

Telegram settings​

These are not environment variables, but sign-in fails without them:

  • Mini App URL — in BotFather, point each bot's Mini App (or menu button) at the HTTPS origin that serves that app's build.
  • Webhook — set each bot's webhook to https://<api-origin>/webhooks/telegram/<app-id> with secret_token equal to that app's webhookSecret. Contact sharing and bot permission reach the API only this way. See Move Telegram webhooks to the API.
  • One consumer per bot — a bot with a webhook cannot also be polled by the local launchers.

Supabase Auth settings​

Supabase Auth must have a custom OIDC provider whose issuer is CHANNEL_AUTH_ISSUER_URL, whose client ID is CHANNEL_AUTH_ASSERTION_AUDIENCE, and whose identifier is CHANNEL_AUTH_SUPABASE_PROVIDER. The API workspace's npm run auth:provider script registers it using the operator-only SUPABASE_SECRET_KEY, which never belongs in the API runtime. See Mini App OIDC flow.

Example: local development with one phone​

  1. Run the API on 127.0.0.1:3000 with channel authentication configured. The issuer must be HTTPS even locally, so put the API behind a tunnel or TLS proxy and use that origin as CHANNEL_AUTH_ISSUER_URL.
  2. Professional app: leave VITE_API_URL empty, run npm run dev, and tunnel port 5173. The proxy forwards /auth and /professional to the API.
  3. Client app: set VITE_API_URL to the API's public HTTPS origin, run npm run dev, and tunnel port 4178.
  4. Point each bot's Mini App URL at its tunnel, and each webhook at the API.

Expected result: opening either bot's Mini App shows real account data with no sample-data banner. A banner means the page received no launch data.