Production-ready Telegram bot backend for job matching on Vercel using:
- Node.js + TypeScript
- Vercel Serverless Functions
- PostgreSQL + Prisma
- webhook-based Telegram integration
api/
webhook.ts
src/
bot/
commands.ts
handler.ts
config/
env.ts
db/
prisma.ts
repositories/
candidate.repo.ts
vacancy.repo.ts
services/
matching.service.ts
telegram.service.ts
types/
telegram.ts
utils/
logger.ts
prisma/
schema.prisma
- handles Telegram webhook updates on
/api/webhook - saves Telegram users into PostgreSQL
- accepts resume JSON from candidates
- matches by
cityandskills - returns top 3 vacancies
Send one message to the bot with JSON like:
{
"name": "Ivan Ivanov",
"phone": "+375291234567",
"city": "Minsk",
"skills": ["sales", "excel", "crm"]
}Create .env.local:
BOT_TOKEN=your_telegram_bot_token
DATABASE_URL=postgresql://user:password@host:5432/dbname?schema=public
TELEGRAM_WEBHOOK_SECRET=your_random_secret- Install dependencies:
npm install- Generate Prisma client:
npm run prisma:generate- Push schema to PostgreSQL:
npm run prisma:push- Run locally:
npm run devVercel local dev will expose the webhook endpoint at:
http://localhost:3000/api/webhook
To test with Telegram locally, use a tunnel such as ngrok or cloudflared.
- Create a PostgreSQL database compatible with Vercel deployment. Recommended: Vercel Postgres, Neon, Supabase, or any managed PostgreSQL.
- Import the project into Vercel.
- Set environment variables in Vercel:
BOT_TOKENDATABASE_URL
- Run Prisma schema deployment:
npx prisma db pushFor managed environments with migrations, prefer:
npm run prisma:migrate:deploy- Deploy.
Your webhook URL will be:
https://your-domain.vercel.app/api/webhook
Use this request after deployment:
curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=https://your-domain.vercel.app/api/webhook&secret_token=<YOUR_SECRET>"Check webhook info:
curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getWebhookInfo"- The function is stateless and serverless-safe.
- The webhook responds immediately after processing one update.
- No polling or background workers are used.
- Matching is intentionally simple and fast.
- Duplicate Telegram updates are ignored through persistent
update_idtracking. - Webhook secret validation is supported through
TELEGRAM_WEBHOOK_SECRET.