How to Use an AI API: A Practical Guide for Web Developers

Adding AI features to a web application no longer requires training your own models or running GPU clusters. Nearly every major AI capability—text generation, chat, summarization, embeddings, image analysis—is available through a hosted AI API that you can call from a few lines of code. The hard part is not the model itself; it is understanding how requests, authentication, streaming, error handling, and cost control fit together in a real production app. This guide walks through the entire process of using an AI API in a web project, from your first "hello world" request to patterns that hold up under real traffic.

Prerequisites and Key Concepts

Before writing any code, you need three things: an API key from a provider, a runtime that can make HTTPS requests, and a basic mental model of how these APIs work.

Most modern AI APIs, including the OpenAI API and the Anthropic API, follow a similar shape: you send a JSON payload describing a conversation or a prompt, and you receive a JSON response containing generated text plus metadata about token usage. If you understand one, you can adapt to others quickly. Use the OpenAI Chat Completions reference and Anthropic API overview to check each provider's request format. Their authentication headers, parameters and response schemas are not interchangeable.

Two concepts matter most:

Tokens. Models process text in tokens, roughly word fragments. Both your input and the model's output count toward the context window and your bill. A long system prompt that you resend on every request costs money every time, which is a common source of surprise invoices.

Rate limits. Free and entry-tier plans throttle requests per minute and tokens per minute. Your code should expect HTTP 429 responses and handle them gracefully rather than assuming every call succeeds.

One architectural rule outweighs everything else: never call AI APIs directly from browser-side code with your real API key. Anyone can read frontend JavaScript, and a leaked key means someone else spends your budget. Always route requests through your own backend or a serverless function.

Making Your First API Call

Let's build a minimal Next.js Pages API route that takes a user's question and returns a model response. Save it as pages/api/ask.js and run it in the Node.js runtime of an existing Next.js Pages Router project. Next.js supplies parsed request bodies and the response helpers used here; this is not a portable Express, Deno or edge handler. Express would need route registration and JSON body-parsing middleware.

The request illustrates Chat Completions with gpt-4o-mini, not a recommendation to use that model for every new application. Check the model documentation and your account access before using it. OpenAI recommends considering the Responses API for new projects; its request and response schema differs from this example.

// pages/api/ask.js - Next.js Pages API route, Node.js runtime
export default async function handler(req, res) {
  if (req.method !== "POST") {
    return res.status(405).json({ error: "Method not allowed" });
  }

  const { question } = req.body ?? {};
  if (typeof question !== "string" || !question.trim() || question.length > 2000) {
    return res.status(400).json({ error: "Invalid question" });
  }

  if (!process.env.OPENAI_API_KEY) {
    return res.status(500).json({ error: "Server configuration error" });
  }

  try {
    const response = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      signal: AbortSignal.timeout(20000),
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
      body: JSON.stringify({
        model: "gpt-4o-mini",
        messages: [
          { role: "system", content: "You are a concise assistant for a developer docs site." },
          { role: "user", content: question },
        ],
        max_completion_tokens: 500,
        temperature: 0.7,
      }),
    });

    if (response.status === 429) {
      return res.status(429).json({ error: "Rate limited, please retry shortly" });
    }

    if (!response.ok) {
      return res.status(502).json({ error: "AI provider request failed" });
    }

    const data = await response.json();
    const answer = data.choices?.[0]?.message?.content;

    if (data.choices?.[0]?.finish_reason !== "stop" ||
        typeof answer !== "string" || !answer.trim()) {
      return res.status(502).json({ error: "Unexpected API response" });
    }

    res.status(200).json({ answer });
  } catch (err) {
    console.error("AI API request failed:", err);
    res.status(500).json({ error: "Internal server error" });
  }
}

Notice what this minimal example already does beyond the bare API call: it validates input, caps input length, sets a token limit to bound costs, treats rate limits as a distinct case, and never exposes the key. These habits reduce common integration mistakes. Before exposing this endpoint publicly, add application authentication, per-user quotas and abuse protection; hiding the provider key alone does not prevent someone from repeatedly calling your backend.

The key itself lives in an environment variable, never in source control. On Vercel, for example, you configure environment variables in the project dashboard, and the Vercel platform provides serverless functions that pair naturally with this pattern—your frontend calls /api/ask, and the secret stays server-side.

Streaming Responses for Better UX

Text generation can take several seconds, and waiting for the full response before showing anything feels sluggish. Nearly all major AI APIs support streaming, where tokens arrive incrementally over the HTTP connection. Rendering text as it arrives dramatically improves perceived speed.

With OpenAI-compatible endpoints, you set "stream": true and receive server-sent events. The browser example below assumes a separate /api/ask-stream backend route that parses provider SSE events and sends only UTF-8 text deltas. The non-streaming /api/ask route above does not implement that endpoint. Reading raw provider SSE with this function would display event framing and JSON rather than just the answer:

async function streamAnswer(question, onChunk) {
  const res = await fetch("/api/ask-stream", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ question }),
  });

  if (!res.ok || !res.body) throw new Error("Streaming request failed");
  const reader = res.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    onChunk(decoder.decode(value, { stream: true }));
  }
  const remaining = decoder.decode();
  if (remaining) onChunk(remaining);
}

On the server, you forward the provider's stream to the client, parsing the SSE format (data: {...} lines) and extracting incremental text deltas. Several SDKs and helper libraries, including the Vercel AI SDK, handle this parsing for you and provide React hooks that bind streamed text directly to your UI state—worth considering once you outgrow raw fetch calls.

One caveat: streaming complicates caching and moderation. If you need to inspect or log full responses before the user sees them, streaming undermines that, so decide based on your product's requirements.

Managing Cost, Reliability, and Prompt Quality

Once an AI feature is live, three operational concerns dominate: cost, failure handling, and output consistency.

Cost control. Track token usage from every response (providers return usage data in each completion). Log it per request with a user identifier so you can attribute spend. Set the endpoint-specific output limit: max_completion_tokens in this Chat Completions example, or max_output_tokens for Responses. Providers also impose model limits, but an explicit cap makes your own budget more predictable. For high-traffic features, consider using a smaller, cheaper model for simple tasks and reserving larger models for complex ones.

Retries and timeouts. AI APIs occasionally return transient errors or slow responses. Use exponential backoff for retryable statuses (429, 5xx), set explicit timeouts on your HTTP client, and cap retries at two or three attempts. A user waiting thirty seconds for a retry storm is worse than a fast, honest failure.

Prompt stability. The difference between a demo and a feature is usually the system prompt. Be explicit about output format, length, and tone. If you need structured data—say, JSON for downstream processing—ask for JSON explicitly and validate the output before trusting it. Models sometimes wrap JSON in markdown fences or add commentary, so parse defensively:

function extractJson(text) {
  const match = text.match(/```(?:json)?\s*([\s\S]*?)```/);
  const candidate = match ? match[1] : text;
  try {
    return JSON.parse(candidate);
  } catch {
    return null; // handle invalid output gracefully
  }
}

Finally, remember that model outputs are probabilistic. The same prompt can yield different answers, so never use an AI API for tasks requiring guaranteed correctness—financial calculations, legal determinations, or security decisions—without a deterministic layer verifying the result.

Choosing Between Providers and Models

You do not need to pick one provider forever. The API patterns are similar enough that swapping or mixing providers is easier through a provider adapter, but still requires checking authentication, schemas, streaming events and feature support, especially if you isolate API calls behind a single service module in your codebase.

When evaluating options, weigh these criteria:

  • Capability fit: coding, long documents, vision, and multilingual tasks are not equally strong across models. Check current model documentation rather than relying on older comparisons.
  • Context window: long-document use cases demand large context, but large inputs cost more per request.
  • Latency and streaming quality: interactive chat features benefit from fast first-token responses.
  • Pricing structure: per-token pricing differs significantly between models; estimate your expected volume before committing.
  • Compliance and data handling: if you handle user data, review each provider's data retention and training policies—this varies and matters for regulated products.

A pragmatic approach: build behind a thin abstraction layer, start with one provider's mid-tier model, and benchmark against an alternative only when you have real usage data showing cost or quality problems.

Frequently Asked Questions

Do I need to pay upfront to start using an AI API?

Free tiers, trial credits and payment requirements vary by provider and account, so do not assume free API access. Check current billing requirements before testing. Set application-level quotas and review provider spending controls before launching publicly; dashboard budgets may be alerts rather than hard stops.

Can I call an AI API directly from frontend JavaScript?

Not with your secret key. Browser code is visible to everyone, so any key embedded in it can be stolen and abused. The standard pattern is a backend or serverless function that holds the key and forwards requests. Some providers offer browser-specific mechanisms, but routing through your server remains the safest default.

How do I keep AI API costs under control?

Set the output-token limit supported by your endpoint and model, cache suitable repeated inputs without exposing another user’s data, log token usage per user, and choose the smallest model that meets your quality bar. Reviewing usage dashboards weekly during the first months of a feature catches runaway costs early.

What is the difference between a chat completion and an embedding API?

Chat completion endpoints generate text in response to a conversation or prompt. Embedding endpoints convert text into numeric vectors used for search, clustering, and retrieval-augmented generation (RAG). They serve different purposes and are typically billed differently, so use each for what it is designed for.

How do I handle inconsistent or invalid model outputs?

Write explicit prompts specifying the exact output format, then validate programmatically before using the result. For structured data, request JSON, parse defensively, and fall back to a retry or a friendly error when validation fails. Never assume output shape without checking it.

Conclusion

Using an AI API comes down to a handful of solid habits: keep your keys on the server, validate inputs, bound your token usage, stream for interactive features, and handle failures as a normal part of operation. The API surface is simple enough to learn in an afternoon, but the operational details—cost attribution, retries, prompt discipline—are what separate a fragile demo from a dependable feature. A good next step is to pick one provider, read its official quickstart, and build the small backend endpoint shown above against a real feature in your own project. Once one integration works end to end, adapting to other providers or models becomes a routine change rather than a rewrite.



Transparency Note: Links in this article are not affiliate links. I recommend these tools and platforms based on their relevance to the topic, and no compensation is received for including them.

Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Necessary

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.

Analytics

This website uses Google Analytics to collect anonymous information such as the number of visitors to the site, and the most popular pages.

Keeping this cookie enabled helps us to improve our website.