Telegram-native course platform: sell access, take payments, deliver video + quizzes, and manage everything from an admin panel. Built for Telegram Mini Apps, also works as standalone web.
- Turn your Telegram audience into paying students
- Accept payments: PayPal or Telegram Stars
- Deliver lessons: video (Cloudflare Stream) + markdown
- Quizzes to keep students engaged (and measure progress)
- Admin panel: users, content, basic analytics/support flows
- Multi-language:
en/ru/uk
You run a Telegram community and want to monetize it:
- Upload lessons (markdown + video)
- Set a price (PayPal / Stars)
- Users pay -> get instant access -> watch -> pass quizzes
- You manage everything in admin (users, activity, feedback)
democourse.cookiewhite.beer - full platform in demo mode.
Goal: keep prod predictable (no "works on my machine").
config.yaml+ env are validated with Zod (bad config fails fast)- PayPal webhooks: signature verification (when
env.paypal.webhookIdis set) + rate limiting - Repeated webhooks won't grant access 2x
GET /healthfor monitoring (uptime, memory, env)- Logs for key flows (DB migrations, payments, errors)
- Signed video tokens; frontend retries signed URL fetch with backoff
botShieldblocks common scanners/bots (less noise on the server)
Want more? Enable Redis (caching) and features.hidePublic (gate access: only Telegram entry, no public web).
For developers (setup / docs)
- Frontend: React 19, TypeScript, Vite, Tailwind, Framer Motion
- Backend: Express, TypeScript, SQLite, Redis (optional)
- Integrations: Telegram Bot API, PayPal REST API, Cloudflare Stream
- Node.js >= 20
- npm (or pnpm)
git clone https://github.com/CookieWhiteBear/Course-MiniAPP.git
cd Course-MiniAPP
npm install
cd server
npm install
cd ..npm run dev:cliOr run directly:
npm run dev:cli demo # demo mode, Telegram not required
npm run dev:cli dev # dev mode, Telegram auth requiredThis starts both: frontend 5173 and backend 3001.
Open http://localhost:5173 (demo mode works without Telegram).
Main config lives in config.yaml (root). You can also use env vars (they take priority).
app:
name: My Course Platform
defaultCurrency: USD
env:
nodeEnv: production
demoMode: false
frontendUrl: https://your-domain.com
telegram:
botToken: "your-bot-token"
adminIds: [123456789]
paypal:
clientId: "your-client-id"
secret: "your-secret"
webhookId: "your-webhook-id"
mode: live
courses:
- id: 1
title: My First Course
authorId: main
price: 29.99
starsPrice: 500
visibility: public
authors:
- id: main
name: Your NameFull reference: docs/configuration.md
Courses live in courses/:
courses/
|-- 1/
| |-- 1.md # Lesson 1
| |-- 2.md # Lesson 2
| `-- 3.md # Quiz
`-- 2/
`-- ...
Text:
# Welcome to the Course
Your content in **markdown**.Video:
# Video Lesson
<vid:cloudflare-video-id>
# or local
<vid:video.mp4>Quiz:
<quiz:single>
# What is 2+2?
1. Three
2. Four
3. Five
<q:2>Full format: docs/courses.md
- PayPal: set
env.paypal.webhookId+ webhook URLhttps://your-domain.com/paypal-hook - Telegram Stars: enable payments in @BotFather and set
starsPriceper course
Details: docs/payments.md
npm run build:deployHealthcheck:
curl https://your-domain.com/healthGuide: docs/deployment.md
- Configuration -
config.yamlreference - Courses - content format
- API - REST endpoints
- Frontend - UI architecture
- Database - SQLite schema
- Payments - PayPal + Stars
- Video - Cloudflare Stream
- Deployment - production setup
npm run dev:cli
npm run build
npm run lint
cd server
npm run dev
npm testMIT
