---
name: build-ai-chatbot-api-route
description: 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.
license: CC-BY-4.0
compatibility: Node 18+; examples use a Next.js route handler and the OpenAI SDK
metadata:
  category: backend
  tags: "chatbot,llm,api,nextjs"
  author: johnny-bravo
  version: "1.0"
  updated: "2026-10-31"
  status: published
---

# 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
1. **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 with `NEXT_PUBLIC_`.
2. **Install the SDK.** For example `npm i openai`. Pick the model in an env var such as `OPENAI_MODEL`, so you can change it without a code change.
3. **Create the route.** In Next.js App Router, add `app/api/chat/route.ts` with a `POST` handler. Other frameworks use any POST endpoint.
4. **Validate the input.** Accept `{ messages: [{ role, content }] }` only. Keep the last 20 messages and reject huge inputs (for example over 8,000 characters).
5. **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.
6. **Call the model with streaming on** and return the text as it arrives (see the example).
7. **Handle errors.** Return a friendly message on timeouts or provider errors, and log the real error on the server only.
8. **Add limits before launch.** Use the add-chatbot-guardrails-and-rate-limits skill.

## Example (Next.js + OpenAI)
```ts
// 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."
