Call an AI API from a Server
Now you will connect your chatbot to a real AI model by calling its API from a Node.js server.
What You Need
- Node.js 18 or newer (it has
fetchbuilt in) - An account and an API key from an AI provider
- The provider's base URL and a model name from their documentation
Many providers offer an OpenAI-compatible chat completions endpoint. This means the request and reply have the same shape, so the same code works with different providers by changing the base URL, key and model.
Rule Number One: Keep the Key Secret
An API key is like a password tied to your bank card. Anyone who has it can use the AI at your cost.
| Do | Never |
|---|---|
| Store it in an environment variable | Write it inside your code |
| Use it only on the server | Put it in browser JavaScript or HTML |
Add .env to .gitignore | Push it to GitHub |
| Set a spending limit with the provider | Share it in WhatsApp groups |
Create a file named .env in your project (and never commit it):
Example
AI_API_KEY=paste-your-key-here
AI_BASE_URL=https://api.example-provider.com/v1
AI_MODEL=the-model-name-from-the-docsNode.js 20.6+ can load it with node --env-file=.env server.js. On a hosting service, you add the same variables in its dashboard instead.
The Request
Send a POST request to BASE_URL/chat/completions with the key in the Authorization header:
Example
// ai.js - runs on the server only
async function askAI(messages) {
const response = await fetch(`${process.env.AI_BASE_URL}/chat/completions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.AI_API_KEY}`,
},
body: JSON.stringify({
model: process.env.AI_MODEL,
messages,
temperature: 0.3,
max_tokens: 300,
}),
});
if (!response.ok) {
throw new Error(`AI API error ${response.status}: ${await response.text()}`);
}
const data = await response.json();
return data.choices[0].message.content;
}
module.exports = { askAI };Reading the Reply
The JSON reply looks like this (shortened). The text is in choices[0].message.content:
Example
const data = {
choices: [
{ message: { role: "assistant", content: "Yes, we offer weekend classes." } },
],
usage: { prompt_tokens: 42, completion_tokens: 8 },
};
console.log(data.choices[0].message.content);
console.log("Tokens used:", data.usage.prompt_tokens + data.usage.completion_tokens);Yes, we offer weekend classes. Tokens used: 50
The usage part tells you how many tokens you paid for.
A Chat Endpoint with Express
Now make an endpoint the website can call. Install Express with npm install express, then:
Example
// server.js
const express = require("express");
const { askAI } = require("./ai");
const app = express();
app.use(express.json());
app.use(express.static("public")); // your chat page lives in /public
const SYSTEM = "You are the friendly assistant for a computer institute in Karachi. " +
"Answer briefly. If you do not know, say so and suggest calling the office.";
app.post("/api/chat", async (req, res) => {
const incoming = Array.isArray(req.body.messages) ? req.body.messages : [];
// Accept only user/assistant text messages, and only the last 10
const history = incoming
.filter((m) => (m.role === "user" || m.role === "assistant") && typeof m.content === "string")
.map((m) => ({ role: m.role, content: m.content.slice(0, 2000) }))
.slice(-10);
try {
const reply = await askAI([{ role: "system", content: SYSTEM }, ...history]);
res.json({ reply });
} catch (err) {
console.error(err);
res.status(500).json({ reply: "Sorry, something went wrong. Please try again." });
}
});
app.listen(3000, () => console.log("Chatbot running on http://localhost:3000"));Run it with node --env-file=.env server.js.
Notice that the server adds the system prompt. The browser only sends the user and assistant messages, and the filter throws away anything else (such as a fake system message), so users cannot replace your instructions. Each message is also cut to 2000 characters to control cost.
Handling Errors
| Status | Usual meaning | What to do |
|---|---|---|
| 401 | Wrong or missing key | Check the environment variable |
| 429 | Too many requests or no credit | Wait and retry, check your plan |
| 500+ | Provider problem | Retry later, show a friendly message |
Never send the raw error to the user. Log it on the server and show a short, polite message.
Exercise
Exercise
Where should the AI API key be stored in a website chatbot?
