Skip to main content
Developer GuideMarch 20, 2026·Updated Mar 2026·24 min read

How to Integrate ChatGPT into Your App: Complete Developer Guide

Everything you need to integrate OpenAI's ChatGPT API into your application—from basic setup to production-grade streaming, function calling, embeddings, and cost optimization.

RM

Raman Makkar

CEO, Codazz

Share:

ChatGPT changed the game for AI-powered applications. But moving from playground demos to a production-grade integration requires careful architecture decisions around streaming, error handling, cost management, and security. This guide covers everything.

Whether you're building a customer support chatbot, an AI writing assistant, or a code generation tool, the OpenAI API gives you access to GPT-4o, GPT-4 Turbo, and other models. We'll walk through each step from obtaining your API key to deploying a production-ready integration that handles thousands of concurrent users.

ChatGPT Integration: The 2026 Landscape

OpenAI's API has evolved significantly. In 2026, the ecosystem includes:

  • GPT-4o — The flagship multimodal model supporting text, images, audio, and video inputs with fast response times.
  • GPT-4 Turbo — 128K context window, optimized for complex reasoning tasks and structured outputs.
  • GPT-4o Mini — Cost-effective model for high-volume, lower-complexity tasks at 60x cheaper than GPT-4.
  • Assistants API — Built-in support for threads, file retrieval, code interpreter, and persistent memory.
  • Batch API — 50% cost reduction for non-real-time workloads processed within 24 hours.

Key Decision: Chat Completions vs. Assistants API

Use Chat Completions when you want full control over conversation state, context windows, and prompt engineering. Use the Assistants API when you need built-in file search, code interpreter, or persistent threads without managing state yourself.

Step 1: API Setup & Authentication

Start by creating an OpenAI account and generating an API key. Here's the setup for a Node.js/TypeScript backend:

npm install openai

// src/lib/openai.ts
import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  // Optional: set organization ID
  organization: process.env.OPENAI_ORG_ID,
});

export async function chat(messages: OpenAI.ChatCompletionMessageParam[]) {
  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages,
    temperature: 0.7,
    max_tokens: 4096,
  });
  return response.choices[0].message.content;
}

Environment Variable Security

Never expose your API key to the client. The OpenAI SDK should only run server-side.

# .env.local (never commit this file)
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxxx
OPENAI_ORG_ID=org-xxxxxxxxxxxxxxxxxxxxx

# Next.js API route (app/api/chat/route.ts)
import { NextRequest, NextResponse } from 'next/server';
import { chat } from '@/lib/openai';

export async function POST(req: NextRequest) {
  const { messages } = await req.json();

  // Validate & sanitize input
  if (!Array.isArray(messages) || messages.length === 0) {
    return NextResponse.json({ error: 'Invalid messages' }, { status: 400 });
  }

  const reply = await chat(messages);
  return NextResponse.json({ reply });
}

Step 2: Streaming Responses

Streaming is essential for production apps. Users see tokens appearing in real-time instead of waiting 5-15 seconds for a complete response. This dramatically improves perceived performance and user engagement.

// Server: app/api/chat/stream/route.ts
import OpenAI from 'openai';

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

export async function POST(req: Request) {
  const { messages } = await req.json();

  const stream = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages,
    stream: true,
  });

  const encoder = new TextEncoder();
  const readable = new ReadableStream({
    async start(controller) {
      for await (const chunk of stream) {
        const text = chunk.choices[0]?.delta?.content || '';
        controller.enqueue(encoder.encode(`data: ${JSON.stringify({ text })}\n\n`));
      }
      controller.enqueue(encoder.encode('data: [DONE]\n\n'));
      controller.close();
    },
  });

  return new Response(readable, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      Connection: 'keep-alive',
    },
  });
}

Client-Side Stream Consumption

// Client: hooks/useChat.ts
export function useChat() {
  const [response, setResponse] = useState('');
  const [isStreaming, setIsStreaming] = useState(false);

  const sendMessage = async (messages: Message[]) => {
    setIsStreaming(true);
    setResponse('');

    const res = await fetch('/api/chat/stream', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ messages }),
    });

    const reader = res.body?.getReader();
    const decoder = new TextDecoder();

    while (reader) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      const lines = chunk.split('\n').filter(l => l.startsWith('data: '));

      for (const line of lines) {
        const data = line.slice(6);
        if (data === '[DONE]') break;
        const { text } = JSON.parse(data);
        setResponse(prev => prev + text);
      }
    }
    setIsStreaming(false);
  };

  return { response, isStreaming, sendMessage };
}

Step 3: Function Calling (Tool Use)

Function calling lets ChatGPT invoke your backend functions—querying databases, calling APIs, updating records—turning it from a text generator into an intelligent agent that takes action.

const tools: OpenAI.ChatCompletionTool[] = [
  {
    type: 'function',
    function: {
      name: 'get_order_status',
      description: 'Look up the status of a customer order by order ID',
      parameters: {
        type: 'object',
        properties: {
          order_id: { type: 'string', description: 'The order ID (e.g., ORD-12345)' },
        },
        required: ['order_id'],
      },
    },
  },
  {
    type: 'function',
    function: {
      name: 'search_products',
      description: 'Search product catalog by query',
      parameters: {
        type: 'object',
        properties: {
          query: { type: 'string' },
          category: { type: 'string', enum: ['electronics', 'clothing', 'home'] },
          max_price: { type: 'number' },
        },
        required: ['query'],
      },
    },
  },
];

// Handle tool calls in a loop
async function handleWithTools(messages: Message[]) {
  let response = await openai.chat.completions.create({
    model: 'gpt-4o', messages, tools, tool_choice: 'auto',
  });

  while (response.choices[0].finish_reason === 'tool_calls') {
    const toolCalls = response.choices[0].message.tool_calls!;
    messages.push(response.choices[0].message);

    for (const call of toolCalls) {
      const result = await executeFunction(call.function.name,
        JSON.parse(call.function.arguments));
      messages.push({
        role: 'tool', tool_call_id: call.id,
        content: JSON.stringify(result),
      });
    }

    response = await openai.chat.completions.create({
      model: 'gpt-4o', messages, tools,
    });
  }
  return response.choices[0].message.content;
}

Pro Tip: Parallel Function Calls

GPT-4o can invoke multiple functions simultaneously. If a user asks "Show me my order status and recommend similar products," the model will call both get_order_status and search_products in parallel, reducing round trips.

Step 4: Embeddings & RAG (Retrieval-Augmented Generation)

Out-of-the-box, ChatGPT only knows its training data. To make it answer questions about your data—internal docs, product catalogs, knowledge bases—you need RAG. The pattern is: embed your documents, store vectors in a database, retrieve relevant chunks at query time, and pass them as context.

// Generate embeddings
const embedding = await openai.embeddings.create({
  model: 'text-embedding-3-large',
  input: 'Your document text here...',
  dimensions: 1536, // Reduce dimensions for faster search
});

const vector = embedding.data[0].embedding; // Float array

// Store in Pinecone / pgvector / Supabase
await vectorDB.upsert({
  id: 'doc-123',
  values: vector,
  metadata: { source: 'product-docs', title: 'Setup Guide' },
});

// RAG query flow
async function ragQuery(userQuestion: string) {
  // 1. Embed the question
  const qEmbed = await openai.embeddings.create({
    model: 'text-embedding-3-large',
    input: userQuestion, dimensions: 1536,
  });

  // 2. Search vector DB for relevant chunks
  const results = await vectorDB.query({
    vector: qEmbed.data[0].embedding,
    topK: 5, includeMetadata: true,
  });

  // 3. Build context from retrieved chunks
  const context = results.matches
    .map(m => m.metadata.text).join('\n---\n');

  // 4. Send to ChatGPT with context
  return openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [
      { role: 'system', content: `Answer based on this context:\n${context}` },
      { role: 'user', content: userQuestion },
    ],
  });
}

Choosing a Vector Database

Pinecone

Fully managed, serverless, scales to billions of vectors. Best for teams that want zero ops.

pgvector

PostgreSQL extension. Great if you already use Postgres. Self-hosted, cost-effective.

Weaviate

Open-source, hybrid search (vector + keyword). Good for complex retrieval needs.

Supabase

pgvector built-in with auth, storage, and edge functions. Full-stack developer favorite.

Step 5: Cost Optimization

OpenAI costs can spiral quickly at scale. A single GPT-4o call costs ~$5 per million input tokens, and $15 per million output tokens. At 10,000 daily users, that adds up fast. Here are proven strategies to control costs:

Model Routing

Use GPT-4o Mini ($0.15/1M input) for simple tasks like classification, summarization, and FAQ. Reserve GPT-4o ($5/1M input) for complex reasoning. Route based on query complexity.

Prompt Caching

OpenAI automatically caches repeated prompt prefixes. Structure your system prompts to maximize cache hits—put static instructions first, dynamic content last. Cached tokens cost 50% less.

Context Window Management

Don't send the entire conversation history every time. Summarize older messages, keep only the last 10-20 exchanges, and use embeddings to retrieve relevant context on-demand.

Batch API

For non-real-time workloads (content generation, data processing, analysis), use the Batch API for 50% cost reduction. Results are returned within 24 hours.

Response Caching

Cache identical or near-identical queries with Redis or a CDN. For FAQ-style questions, cache hit rates can exceed 40%, cutting API costs substantially.

Token Limits

Set max_tokens to prevent runaway responses. A 500-token limit is often sufficient for customer support replies. Set per-user daily token budgets.

// Smart model routing example
function selectModel(query: string, complexity: number): string {
  if (complexity < 0.3) return 'gpt-4o-mini';    // Simple queries
  if (complexity < 0.7) return 'gpt-4o-mini';     // Medium queries
  return 'gpt-4o';                                 // Complex reasoning
}

// Estimate complexity with a fast classifier
async function estimateComplexity(query: string): Promise<number> {
  const res = await openai.chat.completions.create({
    model: 'gpt-4o-mini',
    messages: [
      { role: 'system', content: 'Rate query complexity 0-1. Reply with number only.' },
      { role: 'user', content: query },
    ],
    max_tokens: 5, temperature: 0,
  });
  return parseFloat(res.choices[0].message.content || '0.5');
}

Step 6: Rate Limiting & Error Handling

OpenAI enforces rate limits based on your tier (RPM: requests per minute, TPM: tokens per minute). You also need to protect your own API from abuse. Here's a robust approach:

import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(20, '1 m'), // 20 requests per minute
  analytics: true,
});

// Middleware for rate limiting
export async function POST(req: NextRequest) {
  const ip = req.headers.get('x-forwarded-for') ?? '127.0.0.1';
  const { success, limit, reset, remaining } = await ratelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: 'Too many requests' },
      { status: 429, headers: {
        'X-RateLimit-Limit': limit.toString(),
        'X-RateLimit-Remaining': remaining.toString(),
        'X-RateLimit-Reset': reset.toString(),
      }},
    );
  }

  // Proceed with OpenAI call...
}

// Retry with exponential backoff for OpenAI errors
async function callWithRetry(fn: () => Promise<any>, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error: any) {
      if (error.status === 429 || error.status === 500) {
        const delay = Math.pow(2, i) * 1000 + Math.random() * 1000;
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Step 7: Production Best Practices

Content Moderation

Use OpenAI's Moderation API to filter harmful inputs before sending to GPT. It's free and catches hate speech, violence, and self-harm content.

Structured Outputs

Use JSON mode or Zod schemas with response_format to guarantee valid JSON responses. This eliminates parsing errors in production pipelines.

Observability

Log every request/response with Langfuse, LangSmith, or custom logging. Track latency, token usage, error rates, and user satisfaction. Set up alerts for cost anomalies.

Prompt Versioning

Store prompts in a database or config file, not hardcoded. Version them like code. A/B test different prompts. Use prompt management tools like Langfuse or Helicone.

Graceful Degradation

If OpenAI is down, fall back to cached responses or a simpler local model. Never show users a raw error. Queue requests and retry.

Security Hardening

Implement prompt injection defense: validate inputs, use system prompts to establish boundaries, filter outputs for PII leakage, and audit all AI-generated content before displaying.

Production Checklist

  • API key stored in environment variables, rotated quarterly
  • Rate limiting on both user-facing API and OpenAI calls
  • Content moderation on inputs and outputs
  • Structured output validation with Zod schemas
  • Request/response logging with cost tracking
  • Fallback strategy when OpenAI API is unavailable
  • Per-user token budgets and spending alerts
  • Prompt injection testing and input sanitization

Why Teams Choose Codazz for AI Integration

At Codazz, we've shipped production ChatGPT integrations for startups and enterprises across fintech, healthcare, and e-commerce. Our team handles the full stack—from prompt engineering and RAG pipelines to streaming UIs and cost optimization.

Production-Ready

We build AI integrations that handle 10K+ concurrent users with proper error handling, caching, and fallbacks.

Cost-Optimized

Smart model routing, prompt caching, and response caching typically cut OpenAI costs by 40-60%.

Rapid Delivery

From proof-of-concept to production in 4-8 weeks. We move fast without cutting corners on security.

Frequently Asked Questions

How much does it cost to use the ChatGPT API?

GPT-4o costs $5 per million input tokens and $15 per million output tokens. GPT-4o Mini is significantly cheaper at $0.15/$0.60 per million tokens. A typical customer support chatbot handling 1,000 conversations/day costs $50-$200/month with proper optimization (model routing, caching, token limits).

Should I use the Chat Completions API or the Assistants API?

Use Chat Completions for maximum control over conversation state, prompt engineering, and cost. Use the Assistants API if you need built-in file search, code interpreter, or persistent conversation threads without managing state yourself. Most production apps start with Chat Completions.

How do I prevent prompt injection attacks?

Layer your defenses: (1) Use strong system prompts with clear boundaries, (2) Validate and sanitize user inputs, (3) Use OpenAI's Moderation API, (4) Implement output filtering for PII/sensitive data, (5) Use structured outputs to constrain response format, (6) Monitor for anomalous patterns in production.

Can I fine-tune GPT-4 for my specific use case?

Yes, OpenAI supports fine-tuning for GPT-4o and GPT-4o Mini. However, start with prompt engineering and RAG first&mdash;fine-tuning is typically needed only when you require a specific output style/format, need to reduce token usage by encoding knowledge into the model, or have a specialized domain where few-shot prompting falls short.

What is the maximum context window for GPT-4?

GPT-4 Turbo supports 128K tokens (~300 pages of text). GPT-4o supports 128K tokens as well. However, sending maximum context every request is expensive. Best practice: use RAG to retrieve only relevant context (typically 2-5K tokens), keeping costs low while maintaining accuracy.

Need Help Integrating ChatGPT?

Get a free technical consultation. We'll review your use case, recommend the right architecture, and provide a detailed implementation plan.

Start Your AI Integration with Codazz