OpenAI API
The most widely used LLM API. OpenAI provides GPT-4o (text + vision), Whisper (audio), embeddings, fine-tuning, and DALL·E (images). This sheet is the practical reference for calling the API, handling responses, and building reliable applications.
Table of Contents
Installation / Setup
pip install openai # or: uv add openai
export OPENAI_API_KEY="YOUR_API_KEY" # never commit real keys
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY") # or reads OPENAI_API_KEY env var
Core Syntax
Chat completions (the core endpoint)
response = client.chat.completions.create(
model="gpt-4o", # or gpt-4o-mini, o3, o3-mini
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain machine learning in one paragraph."},
],
temperature=0.7,
max_tokens=500,
)
print(response.choices[0].message.content)
print(response.usage) # PromptTokens, CompletionTokens, TotalTokens
Models available
| Model |
Context |
Best for |
Cost |
gpt-4o |
128K |
General, multimodal, complex reasoning |
$$$ |
gpt-4o-mini |
128K |
Fast, cheap, good for most tasks |
$ |
o3 |
128K |
Hard reasoning, math, code |
$$$$ |
o3-mini |
128K |
Reasoning at lower cost |
$$ |
gpt-4o-audio |
128K |
Audio input/output |
$$$ |
dall-e-3 |
— |
Image generation |
$$ |
# system — sets behavior
{"role": "system", "content": "Answer in 3 bullet points."}
# user — the input
{"role": "user", "content": "What is pandas?"}
# assistant — previous model output (multi-turn)
{"role": "assistant", "content": "Pandas is a Python library for data analysis."}
# tool — function call result
{"role": "tool", "tool_call_id": "call_abc123", "content": '{"temp": 72}'}
Vision (image understanding)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{"type": "image_url", "image_url": {
"url": "https://example.com/photo.jpg",
"detail": "high" # "low" for faster/cheaper
}},
],
}],
)
# or from a local file
import base64
with open("image.jpg", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image."},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
],
}],
)
Streaming
stream = client.chat.completions.create(
model="gpt-4o",
messages=messages,
stream=True,
)
full_response = ""
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content:
full_response += delta.content
print(delta.content, end="", flush=True)
tools = [{
"type": "function",
"function": {
"name": "get_stock_price",
"description": "Get the current stock price for a ticker symbol.",
"parameters": {
"type": "object",
"properties": {
"ticker": {"type": "string", "description": "Stock ticker, e.g. AAPL"},
},
"required": ["ticker"],
},
},
}]
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What's the price of AAPL?"}],
tools=tools,
tool_choice="auto",
)
# handle the tool call
tool_call = response.choices[0].message.tool_calls[0]
print(tool_call.function.name) # "get_stock_price"
print(tool_call.function.arguments) # '{"ticker": "AAPL"}'
# send the result back
import json
result = json.dumps({"price": 195.50, "currency": "USD"})
messages.append(response.choices[0].message)
messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": result})
JSON mode
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "List 3 programming languages with their years."}],
response_format={"type": "json_object"},
)
# response.choices[0].message.content is valid JSON
Embeddings
response = client.embeddings.create(
model="text-embedding-3-small", # 1536 dims, fast
# model="text-embedding-3-large", # 3072 dims, better
input=["Hello world", "Testing embeddings"],
)
vectors = [e.embedding for e in response.data]
Fine-tuning
# upload training data
file = client.files.create(file=open("train.jsonl", "rb"), purpose="fine-tune")
# create a fine-tuning job
job = client.fine_tuning.jobs.create(
training_file=file.id,
model="gpt-4o-mini-2024-07-18",
hyperparameters={"n_epochs": 3},
)
print(job.id)
# check status
status = client.fine_tuning.jobs.retrieve(job.id)
print(status.status) # "succeeded"
Practical Examples
Example 1 — Customer support bot with function calling
from openai import OpenAI
import json
client = OpenAI(api_key="YOUR_API_KEY")
tools = [{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Look up an order by order ID",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
},
}]
def handle_customer_message(user_msg):
messages = [
{"role": "system", "content": "You are a customer support agent. Use tools to look up orders."},
{"role": "user", "content": user_msg},
]
response = client.chat.completions.create(
model="gpt-4o", messages=messages, tools=tools, tool_choice="auto")
msg = response.choices[0].message
if msg.tool_calls:
# execute tool and return result
args = json.loads(msg.tool_calls[0].function.arguments)
order_data = {"status": "shipped", "tracking": "12345"} # fake result
messages.append(msg)
messages.append({"role": "tool", "tool_call_id": msg.tool_calls[0].id,
"content": json.dumps(order_data)})
final = client.chat.completions.create(model="gpt-4o", messages=messages)
return final.choices[0].message.content
return msg.content
Example 2 — Image analysis pipeline
import base64
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY")
def analyze_image(path, question="What do you see?"):
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": question},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
],
}],
max_tokens=1000,
)
return response.choices[0].message.content
Example 3 — Batch embeddings for search
from openai import OpenAI
import numpy as np
client = OpenAI(api_key="YOUR_API_KEY")
def get_embeddings(texts, model="text-embedding-3-small"):
response = client.embeddings.create(model=model, input=texts)
return np.array([e.embedding for e in response.data])
docs = ["Python for data science", "JavaScript for web dev", "R for statistics"]
doc_vecs = get_embeddings(docs)
query = "data analysis tools"
q_vec = get_embeddings([query])[0]
sims = np.dot(doc_vecs, q_vec) / (np.linalg.norm(doc_vecs, axis=1) * np.linalg.norm(q_vec))
print(docs[np.argmax(sims)])
Common Patterns
def extract(text, schema_description):
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Extract info as JSON. Schema: {schema_description}"},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
temperature=0.0,
)
return json.loads(response.choices[0].message.content)
Pattern: retry on rate limits
import time
def safe_call(func, max_retries=3):
for i in range(max_retries):
try:
return func()
except openai.RateLimitError:
time.sleep(2 ** i * 5)
raise Exception("Rate limit exceeded after retries")
Pattern: multi-model routing
def route_task(task_type, text):
if task_type == "extraction":
return client.chat.completions.create(model="gpt-4o-mini", messages=messages, temperature=0)
elif task_type == "reasoning":
return client.chat.completions.create(model="o3", messages=messages)
elif task_type == "creative":
return client.chat.completions.create(model="gpt-4o", messages=messages, temperature=0.9)
Best Practices
- Always set
response_format={"type": "json_object"} for structured output — don't just ask in the prompt.
- Use
gpt-4o-mini for classification, extraction, and simple tasks — much cheaper and faster.
- Use
gpt-4o or o3 for complex reasoning, multi-step analysis, and vision tasks.
- System messages are cheap — use them to constrain output format and behavior.
- Streaming is essential for UX — always
stream=True for user-facing applications.
- Cache API responses when possible — same input + temperature 0 = same output.
- Always implement retry with backoff for rate limits.
- Use
tool_choice="required" to force function calling when you need it.
- Keep function definitions clear — the model chooses based on descriptions.
Common Mistakes
| Mistake |
Fix |
Using gpt-4o for every task |
Use gpt-4o-mini for simple tasks to save cost |
Not checking response.usage |
Monitor token usage to control costs |
| Hard-coding API keys |
Use environment variables (OPENAI_API_KEY) |
| Not streaming for user-facing apps |
Add stream=True and iterate on chunks |
| Ignoring rate limits |
Check x-ratelimit-* headers; implement backoff |
| Sending images without resizing |
Resize large images before base64 encoding |
Not handling finish_length truncation |
Increase max_tokens or continue generation |
Troubleshooting
| Symptom |
Cause / Fix |
AuthenticationError |
Invalid API key — check OPENAI_API_KEY |
RateLimitError |
Too many requests — implement backoff |
ContextLengthExceeded |
Input too long — truncate or use longer-context model |
| Model returns truncated output |
Hit max_tokens — increase it |
| JSON parse error on response |
Use response_format={"type": "json_object"} |
| Model ignores function calling |
Ensure tools parameter is passed correctly |
| Slow first response |
Cold start — first API call is slower |
| High costs |
Switch to gpt-4o-mini for simple tasks; cache results |
Official Documentation
Last Updated
2026-09-06 — Initial version.