ChatGPT API Integration — Complete Developer Guide 2026
Advertisement
Introduction
Why This Matters
The ChatGPT API unlocks capabilities the web interface cannot offer: programmatic control over prompts, response streaming, function calling, batch processing, and per-request cost management. For any production application — a code review bot, a documentation generator, a customer support tool — the API is the correct approach. This guide covers everything from your first API call to production-ready patterns.
Account Setup and Authentication
Start at platform.openai.com. Create an account, navigate to API Keys, and generate a key. Store it as an environment variable — never hard-code it in source files.
# .env file (never commit this to git)
OPENAI_API_KEY=sk-proj-...
# Python: python-dotenv loads it automatically
# Node.js: dotenv loads it automaticallyInstall the SDK:
pip install openai # Python
npm install openai # Node.js / TypeScriptYour First API Call
from openai import OpenAI
# Reads OPENAI_API_KEY from environment automatically
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a concise technical assistant."},
{"role": "user", "content": "Explain what a JWT token is in two sentences."},
],
max_tokens=200,
temperature=0.3,
)
print(response.choices[0].message.content)
print(f"Tokens used: {response.usage.total_tokens}")The response text lives in choices[0].message.content. Track response.usage.total_tokens — it directly determines your bill.
Multi-Turn Conversations
The OpenAI API is stateless. You maintain conversation history by appending each exchange to the messages list and resending the full array.
from openai import OpenAI
client = OpenAI()
class CodingAssistant:
def __init__(self):
self.messages = [
{
"role": "system",
"content": (
"You are a senior Python developer. "
"Give concise working code examples. "
"Ask for clarification when requirements are ambiguous."
),
}
]
def chat(self, user_input: str) -> str:
self.messages.append({"role": "user", "content": user_input})
response = client.chat.completions.create(
model="gpt-4o",
messages=self.messages,
max_tokens=1024,
temperature=0.2,
)
reply = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": reply})
return reply
assistant = CodingAssistant()
print(assistant.chat("How do I validate an email address in Python?"))
print(assistant.chat("Can you show me how to test that function?"))Streaming Responses
Streaming returns tokens as they are generated, enabling responsive UIs that do not wait for the full response.
import OpenAI from 'openai';
const client = new OpenAI();
async function streamCodeExplanation(code: string): Promise<string> {
const stream = await client.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: 'Explain code clearly, step by step.',
},
{
role: 'user',
content: `Explain this code:\n\n\`\`\`\n${code}\n\`\`\``,
},
],
stream: true,
max_tokens: 800,
});
let fullResponse = '';
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content ?? '';
process.stdout.write(delta);
fullResponse += delta;
}
return fullResponse;
}Function Calling
Function calling lets the model invoke actions in your application — querying databases, calling external APIs, or triggering computations — when it decides that data is needed to answer the user.
import json
from openai import OpenAI
client = OpenAI()
tools = [
{
"type": "function",
"function": {
"name": "get_package_info",
"description": "Get version and description of an npm or PyPI package",
"parameters": {
"type": "object",
"properties": {
"package_name": {"type": "string"},
"registry": {
"type": "string",
"enum": ["npm", "pypi"],
},
},
"required": ["package_name", "registry"],
},
},
}
]
def get_package_info(package_name: str, registry: str) -> str:
import urllib.request, json as _json
if registry == "npm":
url = f"https://registry.npmjs.org/{package_name}/latest"
else:
url = f"https://pypi.org/pypi/{package_name}/json"
with urllib.request.urlopen(url) as r:
data = _json.loads(r.read())
version = data.get("version") or data.get("info", {}).get("version")
return f"{package_name} @ {version}"
def agent_loop(question: str) -> str:
messages = [{"role": "user", "content": question}]
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto",
)
choice = response.choices[0]
if choice.finish_reason != "tool_calls":
return choice.message.content
messages.append(choice.message)
for tc in choice.message.tool_calls:
args = json.loads(tc.function.arguments)
result = get_package_info(**args)
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": result,
})
print(agent_loop("What is the latest version of the requests library on PyPI?"))Error Handling and Retries
Build retry logic with exponential backoff for rate-limit and server errors.
import time
from openai import OpenAI, RateLimitError, APIStatusError
client = OpenAI()
def call_with_retry(messages, model="gpt-4o", max_retries=3):
for attempt in range(max_retries):
try:
return client.chat.completions.create(
model=model,
messages=messages,
max_tokens=1024,
)
except RateLimitError:
wait = 2 ** attempt # 1s, 2s, 4s
print(f"Rate limited. Waiting {wait}s (attempt {attempt + 1})...")
time.sleep(wait)
except APIStatusError as e:
if e.status_code >= 500:
time.sleep(2 ** attempt)
else:
raise # Do not retry client errors (4xx)
raise RuntimeError(f"API call failed after {max_retries} attempts")Common Mistakes
- Hard-coding API keys in source files or committing
.envto git - Not setting
max_tokens— a runaway response can consume expensive tokens - Using
gpt-4ofor tasks wheregpt-4o-miniperforms equally well (costs ~20x more) - Sending the full conversation history without pruning — old messages waste tokens and inflate cost
- Not handling rate limit errors — applications crash under production load without retry logic
Best Practices
- Use
gpt-4o-minifor high-volume classification, extraction, and summarization tasks - Cache responses for repeated identical prompts using a hash of the message array as the cache key
- Set billing alerts at platform.openai.com before any significant load testing
- Log token counts and model names per request to identify cost hotspots
- Limit system prompt size — it is resent on every message in the thread
Key Takeaways
- The OpenAI API is stateless — you send the full conversation history on each request
- Streaming (
stream=True) returns tokens incrementally for responsive chat UIs - Function calling lets the model trigger your application logic when it needs real data
gpt-4o-minicosts roughly 20x less thangpt-4oand handles most classification and extraction tasks- Rate limit errors (429) require exponential backoff — build retry logic before any production deployment
- Always set
max_tokensto cap response length and control costs - Token usage in
response.usageshould be logged per request for accurate cost attribution - Never commit API keys to source control — use environment variables or a secrets manager
Advertisement