All articles

OpenAI API Integration: Choose the Right API; Westcode Shows How

Build a production OpenAI integration with backend key safety, the right API primitives, rate limit handling, and a practical Westcode example.

Integrate OpenAI by putting the key on a secure backend, calling the Responses API, and using function calling or Structured Outputs for deterministic actions. Start with the official SDKs, follow production best practices for rate limits and key rotation, and add streaming or stateful conversation handling only once the basic flow works.


TL;DR:

  • Give each client application its own project scoped key, store it in a secrets manager, and set expiration and rotation rules before launch.
  • When moving from Chat Completions, change the request from a messages array to input, and update parsing because responses return structured items.
  • Use retrieval when answers depend on changing private documents; embed small, stable context directly in prompts instead of maintaining a document search index.
  • For temporary failures, wait at least the server’s stated delay and use exponential backoff with jitter; never retry quota or billing errors automatically.
  • Use previous_response_id to carry turns forward without resending full history; choose server storage or zero data retention according to privacy requirements.

Getting started: keys, SDKs, and your first call

The fastest path to a working integration follows a short sequence, and skipping steps here is what causes rewrites later.

  1. Create an OpenAI project and generate an API key scoped to that project, not your personal account.
  2. Store the key in your backend's environment variables or a secrets manager, never in a frontend bundle.
  3. Install the official SDK for your stack (the Node.js or Python libraries cover most use cases) and make a first call to the Responses API from a backend route.
  4. Build a thin proxy endpoint that your frontend calls instead of talking to OpenAI directly, returning only the fields your UI needs.
  5. Add streaming or WebSocket support only once the synchronous flow is stable and you have a concrete latency problem to solve.
  6. Layer in function calling or retrieval once the plain text flow works end to end.

This order matters because each step depends on the last being solid. A streaming layer on top of a broken auth model just hides the problem.

Pro Tip: Test your backend route with a tool like Postman or curl before wiring up any frontend code: isolating the API call from the UI makes early bugs much faster to diagnose.

Backend-first architecture and API key safety

Every OpenAI integration decision starts from one constraint: the key must never reach the browser. Best practices for API key safety are explicit that frontend code exposes anything embedded in it to public inspection, so a middleware or backend layer has to hold the key and make the actual request on the client's behalf.

A reasonable backend pattern includes:

  • A proxy route that accepts a sanitized request from the frontend and attaches the API key server-side.
  • Environment variables or a managed secrets store, rather than configuration files that might get committed to a repository.
  • Key rotation on a schedule, plus expiration settings so a leaked key has a limited window of usefulness.
  • Request validation and rate-limiting at the edge, before anything reaches OpenAI, to control cost and abuse.
  • Audit logging on every call, tied to an internal user or session identifier rather than raw personal data.

Production best practices note that administrators can enforce API key lifetimes and restrict which key types get created at the organization or project level, which is worth setting up before launch rather than after an incident.

For abuse monitoring without exposing personal information, the safety best practices guide recommends sending a safety_identifier, a hashed user or session ID, alongside calls, and pairing that with the free Moderation API to catch unsafe content before it reaches your users.

Statistic Callout: Frontend code that stores an API key exposes it to public inspection according to OpenAI's key safety guidance, which is why every production integration routes requests through a backend instead.

Pro Tip: Give each client application its own project-scoped key rather than one shared key across every service: it makes rotation and revocation far less disruptive when something goes wrong.

Responses API vs. Chat Completions: which to build on

For a new project, the Responses API is the better starting point. It is described as OpenAI's flagship interface, built to support tools, agent-style features, Structured Outputs, and stateful workflows in one primitive, rather than the narrower message-in, message-out shape of Chat Completions.

Migrating or starting fresh involves a few concrete changes:

  • Swap the endpoint and request shape: Responses uses an input structure rather than a flat messages array, though roles and instructions carry over conceptually.
  • Update output parsing, since Responses returns structured items rather than a single choices[0].message.content string.
  • Replace manual conversation-history management with the state strategy Responses supports natively, covered in the next section.
  • Decide early whether you need streaming text, a WebSocket connection, or a simple synchronous call. The WebSocket mode guide is the right reference once you have tool-heavy or long-running workflows, while basic streaming covers most chat UIs.

Chat Completions still works and still gets support, but new projects gain little by starting there when Responses covers the same ground plus built-in tools and schema enforcement.

Wiring the model to your tools and data

Function calling turns a model from a text generator into something that can act on your systems, integrating with a transactional email API and SMS flows for notifications or one-time passcodes. The function calling guide describes it as a multi-step conversation: your app sends a request with a list of available tools, the model returns a function_call item instead of plain text when it decides a tool is needed, your application executes that function, and you send the result back to the model to get a final answer.

  1. Define each function with a clear name, description, and JSON schema for its parameters.
  2. Send that schema alongside the user's request so the model knows what tools exist.
  3. When the model returns a function call, execute the corresponding code in your backend, never on the client.
  4. Return the function's output to the model as the next turn, and let it produce the final response.
  5. For anything production-facing, enable strict mode so the function's output reliably matches your schema instead of drifting.

Structured Outputs extend the same idea to the model's final answer: instead of parsing free text, you define a JSON schema and the response is guaranteed to match it, which removes a whole category of parsing bugs. It is the natural successor to the older JSON mode and is the better default for anything downstream that expects a predictable shape.

Retrieval-augmented generation (RAG) complements function calling rather than replacing it. Use RAG when the answer depends on your own documents or data that changes often; embed context directly in the prompt only when that context is small and stable. A basic similarity search over your document store, paired with a reasonable chunk size, usually beats trying to stuff everything into the prompt.

Pro Tip: When a task needs several sequential tool calls, handle each one explicitly and log the intermediate results: debugging a chain of three function calls after the fact is much harder than catching a bad one in the middle.

Managing conversation state across requests

Each call to the API is stateless on its own, so the model has no memory of previous turns unless you give it one. The conversation state guide frames this as the central shift between a demo and a production system: you have to decide explicitly what context to store and what to send with each new request.

  • Chain turns with previous_response_id so the API handles continuity for you, rather than resending the full history every time.
  • For longer-running assistants, the Conversations API offers a more structured alternative, with compaction strategies that summarize older turns instead of letting the context grow indefinitely.
  • For tool-heavy or long-running sessions, WebSocket mode keeps recent response state in memory and supports multiplexing multiple streams through a stream_id, which cuts latency on workflows with many sequential tool calls.
  • Decide between store=true, which keeps conversation data server-side for continuity, and a zero-data-retention approach with store=false plus encrypted reasoning items, depending on what your privacy requirements allow.

Getting this wrong usually shows up as either a model that "forgets" instructions mid-conversation or a bill that grows faster than expected because every turn resends the entire history.

Handling rate limits, retries, and estimating costs

Rate limits are not an edge case, they are a normal part of running at any real volume. The rate limits guide describes limits in terms of requests per minute and tokens per minute, surfaced through x-ratelimit-* response headers that tell you how close you are to the ceiling before you hit it.

  • Read the rate-limit headers on every response and back off proactively rather than waiting for a 429.
  • Treat the Retry-After header as a minimum wait, not a target, and use exponential backoff with jitter when it is absent.
  • Never retry automatically on quota or billing errors; those need action in your dashboard, not a retry loop.
  • Batch requests where your workflow allows it, and trim max_tokens to what the task actually needs to avoid burning through your tokens-per-minute budget.

Statistic Callout: Retry-After reflects the minimum wait time before a retry should succeed, according to OpenAI's rate limits guide, which makes it a floor for your backoff logic rather than a fixed delay to copy exactly.

For cost estimation, a simple model works well early on: multiply your average tokens per interaction by your expected number of daily active users, then by your model's per-token rate, to get a rough daily figure you can sanity-check against your actual invoice.

Production checklist: scaling, caching, and monitoring

Before anything ships, run through a short list that covers performance, cost, and security together, since these three tend to break in the same incidents.

  1. Cache frequent or repeated responses, and set a clear invalidation rule so stale answers do not linger.
  2. Compress large request bodies with zstd, and enable permessage-deflate on WebSocket connections to cut bandwidth.
  3. Use streaming or WebSocket mode specifically where it improves perceived latency, such as long-form answers or chat interfaces.
  4. Enforce API key governance: set lifetimes, restrict which key types get created, and have a rotation and revocation plan ready before you need it.
  5. Monitor usage continuously so a cost spike or an abuse pattern shows up in a dashboard instead of an invoice.

Production best practices ties these together as a single checklist rather than isolated optimizations, which matches how they tend to fail in practice: a caching gap turns into a cost problem, and a missing key rotation policy turns into a security incident.

Production concern Recommended practice
Latency Streaming or WebSocket mode for long or tool-heavy responses
Bandwidth zstd compression for request bodies, permessage-deflate for WebSocket
Cost control Caching repeated responses, trimming max_tokens
Key security Scoped keys, rotation schedules, usage monitoring

Westcode: a hands-on example of wiring AI into existing systems

When we bring an OpenAI integration into an existing product, we follow the same collaborative process we use for any build: discovery, a scoped architecture plan, then implementation in milestones the client can review as we go.

  • We route every model call through a backend proxy, keeping keys in a secrets manager rather than in any client-facing code.
  • We default to Structured Outputs or strict function calling for anything that feeds another system, since unpredictable formatting breaks downstream logic.
  • Our custom AI integrations write-up walks through how we approach wiring AI into software that already exists.
  • Our HeySEO case study covers how we took an AI product from idea to a working SaaS platform end to end.

When a prototype is enough, and when it is not

A weekend prototype and a production integration solve different problems. The prototype just needs a working call to the model. Production needs state management, retry logic, abuse monitoring, and a cost model, and those add up fast once real users show up.

We typically recommend a scoped engagement once a project needs persistent conversation state, function calling against internal systems, or compliance requirements around data handling. If you are still deciding, ask whether your prototype already tracks rate limits, logs usage, and rotates keys: if the answer is no, that gap is the real project.

— Loic

How Westcode helps you ship an OpenAI integration that holds up in production

We build the backend-first architecture this guide describes as a standard part of our AI & automation work: secure key handling, function calling or Structured Outputs wired to your actual systems, and the monitoring to keep it running once it is live. For teams already using a platform like Housecall Pro or Jobber, our Housecall Pro integrations experience carries over directly to wiring AI into the tools you already run.

A typical engagement starts with a short discovery call, moves to a scoped architecture plan you review before we write code, and ships in milestones so you see working pieces early rather than waiting for one big reveal.

  • Custom AI integrations wired into your existing apps, databases, or internal tools.
  • Full app and platform builds when the integration needs a new frontend, not just a backend.
  • Ongoing support for key rotation, monitoring, and cost tuning once you are live.

If you have a specific integration in mind, reach out through our services page and we will scope what a production-ready version actually takes.

FAQ

What are the five stages of API integration?

A typical integration moves through planning and scoping, authentication and connection setup, data mapping and transformation, testing and validation, and finally deployment with ongoing monitoring. For an OpenAI integration specifically, that maps to key setup, a backend proxy, a Responses API call, function calling or Structured Outputs for reliability, and production monitoring.

What can I do with the OpenAI API?

You can build chat interfaces, document summarization tools, coding assistants, and agents that call your own functions to look up data or take action in other systems. Combining function calling with retrieval over your own documents lets the model act on real, current data rather than just its training knowledge.

How much does the OpenAI API cost?

OpenAI prices API access per token, with rates that vary by model, and the exact figures are published on OpenAI's own pricing page rather than fixed here. A reasonable way to estimate your own cost is to multiply average tokens per interaction by your expected daily users and the per-token rate for your chosen model.

Which API is compatible with OpenAI's models?

OpenAI's own Responses API and Chat Completions API are the primary ways to call its models, and several third-party SDKs and frameworks support one or both formats. New projects generally do better starting with the Responses API, since it covers tools, Structured Outputs, and stateful workflows that Chat Completions handles less directly.

Do I need a backend to use the OpenAI API safely?

Yes. Keeping your API key out of frontend code is a core safety requirement, since anything shipped to a browser can be inspected and extracted, so a backend or middleware layer needs to hold the key and make the actual request.

Written by westcode.io, a small studio in Kelowna and Vancouver.

AI & automation4 min read

QuickBooks Online integrations for trades businesses

How a QuickBooks Online integration works for a trades business: customers, estimates and invoices from the field, the sync patterns that hold up, and the usual traps.

AI & automation4 min read

Housecall Pro integrations: what the API allows and what to build

Housecall Pro has a public API and webhooks on its top plan. What a developer can connect, what's worth building, and the security basics before you hand out a key.

AI & automation3 min read

Custom AI integrations: wiring AI into the software you already use

You don't need new software to use AI. Custom AI integrations wire Claude or GPT into the CRM, inbox and booking system you already have. What it costs.