build-ai-chatbot-api-route
Builds the server side of an AI chatbot - one API route that keeps the model key on the server, adds a system prompt, sends the chat history to an LLM such as OpenAI, Claude or Gemini, and streams the reply back. Use when the user wants to add a chatbot or AI assistant to their app, call the OpenAI API safely, or build a GPT-style chat backend.
Version 1.0 · Updated 2026-10-31
Install in Claude Code, Cursor or Codex (optional)
Only for AI coding tools that read skill folders. Run one line in a terminal, in your project folder. It downloads this skill's text files from TheSkillVault and nothing else; you can read them first with “View raw SKILL.md”.
Claude Code (all your projects)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-ai-chatbot-api-route/raw' -o ~/'.claude/skills/build-ai-chatbot-api-route/SKILL.md'Cursor (this project)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-ai-chatbot-api-route/raw' -o '.cursor/skills/build-ai-chatbot-api-route/SKILL.md'Codex and other Agent Skills tools (this project)
curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/build-ai-chatbot-api-route/raw' -o '.agents/skills/build-ai-chatbot-api-route/SKILL.md'
Or connect the whole library over MCP
Add TheSkillVault to Cursor or add this to your app's MCP settings (read-only; help):
{
"mcpServers": {
"theskillvault": {
"url": "https://theskillvault.ai/mcp"
}
}
}Build an AI chatbot API route
The browser never talks to the AI provider directly. It calls your route, and your route holds the key.
When to use
- Adding a chatbot, support assistant or "ask AI" box to an app.
- You have an API key and need a safe place to use it.
- Your current code calls the AI provider from the browser (move it).
Steps
- Get a key and keep it secret. Put
OPENAI_API_KEY(or your provider's key) in.env.local. Add it to your host's environment settings too. Never prefix it withNEXT_PUBLIC_. - Install the SDK. For example
npm i openai. Pick the model in an env var such asOPENAI_MODEL, so you can change it without a code change. - Create the route. In Next.js App Router, add
app/api/chat/route.tswith aPOSThandler. Other frameworks use any POST endpoint. - Validate the input. Accept
{ messages: [{ role, content }] }only. Keep the last 20 messages and reject huge inputs (for example over 8,000 characters). - Add a system prompt on the server. Say what the bot is for, what it must refuse, and the tone. Users must not be able to replace it.
- Call the model with streaming on and return the text as it arrives (see the example).
- Handle errors. Return a friendly message on timeouts or provider errors, and log the real error on the server only.
- Add limits before launch. Use the add-chatbot-guardrails-and-rate-limits skill.
Example (Next.js + OpenAI)
// app/api/chat/route.ts
import OpenAI from "openai";
const client = new OpenAI(); // reads OPENAI_API_KEY
const SYSTEM = "You are the helpful assistant for Acme. Only answer questions about Acme's product.";
export async function POST(req: Request) {
const { messages } = await req.json();
if (!Array.isArray(messages)) return new Response("Bad request", { status: 400 });
const history = messages.slice(-20).map((m: any) => ({ role: m.role === "assistant" ? "assistant" : "user", content: String(m.content).slice(0, 8000) }));
const stream = await client.responses.create({ model: process.env.OPENAI_MODEL!, instructions: SYSTEM, input: history, stream: true });
const body = new ReadableStream({
async start(c) {
const enc = new TextEncoder();
for await (const ev of stream) if (ev.type === "response.output_text.delta") c.enqueue(enc.encode(ev.delta));
c.close();
},
});
return new Response(body, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
}
Gotchas
- A key in browser code is public. Anyone can copy it and run up your bill.
- Only accept "user" and "assistant" roles from the client. A client-sent "system" message can override your rules.
- Serverless functions have time limits. Streaming keeps long answers from timing out.
Works with any stack
The same shape works with Claude, Gemini or a local model, and with Express, Hono, Remix or SvelteKit. If you use the Vercel AI SDK, streamText does steps 6 and 7 for you. Check its current docs for the exact helpers.
Done when
- The key exists only in server environment variables, and searching the built site for it finds nothing.
curl -N -X POST localhost:3000/api/chat -d '{"messages":[{"role":"user","content":"hi"}]}'streams a reply.- Bad input gets a 400 response, and provider errors show a friendly message.
Example prompt
"Add an AI chatbot to my Next.js site that answers questions about my product, without exposing my OpenAI key."
Licence: CC BY 4.0. Attribution when you reuse it: From TheSkillVault, https://theskillvault.ai, CC BY 4.0