UNPKG

skills-ws

Version:

87 agent skills for AI coding assistants — marketing, growth, web3, dev, design & operations. Built for OpenClaw, Claude Code, Cursor, and Codex.

109 lines (87 loc) • 2.93 kB
## Contents - 6. Webhook Handlers <a name="webhook-handlers"></a> - Next.js Webhook Route - Setting the Webhook - Environment Variables ## 6. Webhook Handlers <a name="webhook-handlers"></a> ### Next.js Webhook Route ```ts // src/app/api/bot/route.ts import { NextRequest, NextResponse } from "next/server"; import { handleWebhook } from "@/lib/bot"; const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; export async function POST(req: NextRequest) { // Validate webhook secret header if (WEBHOOK_SECRET) { const secretHeader = req.headers.get("x-telegram-bot-api-secret-token"); if (secretHeader !== WEBHOOK_SECRET) { console.warn("Webhook secret mismatch — rejecting request"); return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } } try { // grammY's webhookCallback handles the update return await handleWebhook(req); } catch (err) { console.error("Webhook error:", err); // Always return 200 to Telegram to prevent retries return NextResponse.json({ ok: true }); } } // Telegram only sends POST; reject other methods export async function GET() { return NextResponse.json({ status: "Bot webhook active" }); } ``` ### Setting the Webhook ```ts // scripts/set-webhook.ts // Run: npx tsx scripts/set-webhook.ts const BOT_TOKEN = process.env.BOT_TOKEN!; const WEBHOOK_URL = process.env.WEBHOOK_URL!; // e.g. https://yourapp.vercel.app/api/bot const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!; async function setWebhook() { const url = `https://api.telegram.org/bot${BOT_TOKEN}/setWebhook`; const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: WEBHOOK_URL, secret_token: WEBHOOK_SECRET, allowed_updates: [ "message", "callback_query", "pre_checkout_query", ], drop_pending_updates: true, }), }); const data = await res.json(); console.log("setWebhook result:", JSON.stringify(data, null, 2)); // Verify const infoRes = await fetch( `https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo` ); const info = await infoRes.json(); console.log("Webhook info:", JSON.stringify(info, null, 2)); } setWebhook().catch(console.error); ``` ### Environment Variables ```env # .env.local BOT_TOKEN=<your-bot-token-from-botfather> DEV_BOT_TOKEN=<throwaway-bot-token-for-local-mock-signing> # dev only # Keep every bot token server-only. Never use a NEXT_PUBLIC_* bot-token variable. MINI_APP_URL=https://yourapp.vercel.app WEBHOOK_URL=https://yourapp.vercel.app/api/bot WEBHOOK_SECRET=<random-secret-at-least-32-chars> # Database DATABASE_URL=file:local.db TURSO_DATABASE_URL=libsql://your-db.turso.io TURSO_AUTH_TOKEN=<your-turso-auth-token> # Rate limiting (serverless-safe) UPSTASH_REDIS_REST_URL=<your-upstash-rest-url> UPSTASH_REDIS_REST_TOKEN=<your-upstash-rest-token> ``` ---