The Responses API (/v1/responses) is the modern endpoint —
built-in tools, server-side state via previous_response_id, typed streaming events.
Chat Completions (/v1/chat/completions) still works and stays
supported for now, but new features land on Responses first. The legacy Assistants API
is being deprecated in favor of Responses + the conversations primitive.
Default to Responses for anything new.
Install · envSetup
bash
# Python SDK — official client
pip install openai # ≥ 1.50 for Responses API
pip install openai[aiohttp] # async HTTP transport
# Node / TS SDK
npm install openai
# env — picked up automatically
export OPENAI_API_KEY=sk-proj-...
export OPENAI_ORG_ID=org-... # optional, for multi-org
export OPENAI_PROJECT_ID=proj_... # optional, scoped key
Where things liveCommon imports
One client, one namespace. OpenAI() picks up
OPENAI_API_KEY from env. Use AsyncOpenAI in async code.
from openai import OpenAI
Sync client. The 90% case.
from openai import AsyncOpenAI
Async client for FastAPI / asyncio.
from openai import OpenAI; client = OpenAI(api_key="…", base_url="…")
Embed a corpus, retrieve the top chunk by cosine, ground the answer in it. No vector DB, no framework — just the SDK.
python
from openai import OpenAI
import numpy as np
client = OpenAI()
# 1 · Embed your corpus (in real life, store these in a vector DB)
docs = [
"Mumbai's monsoon runs June through September.",
"The Bandra-Worli Sea Link opened in 2009.",
"Vada pav originated in Mumbai in the 1960s.",
]
emb = client.embeddings.create(
model="text-embedding-3-small",
input=docs,
)
vectors = np.array([d.embedding for d in emb.data])
# 2 · Embed the query, cosine-rank
q = "When does the rainy season start?"
qv = np.array(client.embeddings.create(
model="text-embedding-3-small", input=q,
).data[0].embedding)
top = docs[int(np.argmax(vectors @ qv))]
# 3 · Answer grounded in the top chunk
resp = client.responses.create(
model="gpt-4.1-mini",
instructions="Answer using only the context. Cite it verbatim.",
input=f"Context: {top}\n\nQuestion: {q}",
)
print(resp.output_text)
Best practiceGood to know
Use previous_response_id over resending history.
Cheaper, faster, and the model sees the exact prior turns — no token-count drift from your client-side trimming.
Pin the model.gpt-4.1-mini-2025-04-14 won’t change under you;
gpt-4.1-mini-latest will. Pin in prod, float in dev.
Pydantic schemas beat hand-written JSON schemas.responses.parse() handles the schema conversion,
strict-mode flags, and the parse-into-object step in one call.
Common trapsWatch out for
Responses and Chat Completions use different parameter names.max_tokens vs max_output_tokens,
messages vs input,
response_format vs text.format. Don’t copy-paste across endpoints.
Strict structured output rejects extra fields silently.
If the model wants to add a property your schema doesn’t allow, you get a refusal, not a soft warning. Check resp.refusal.
Streaming + tool calls = reassembly required.
Tool arguments arrive as a stream of JSON-string deltas. You must concatenate them before json.loads.
The Chat Completions API (POST /v1/chat/completions) takes a messages array with alternating user and assistant turns and returns the model's next message. It supports GPT-4o, GPT-4o-mini, and o-series reasoning models. Pass temperature, max_tokens, and response_format to control output style and format.
What is the difference between the Responses API and Chat Completions?
The Responses API (POST /v1/responses, launched 2025) is a newer stateful API with built-in tools (web search, code interpreter, file search) and automatic conversation state management. Chat Completions is stateless — you manage the message history yourself. Use Responses for agentic workflows; Chat Completions for fine-grained control.
How do I use function calling in the OpenAI API?
Pass a tools array where each tool has a type: "function", a name, a description, and a parameters JSON Schema. When the model decides to call a function, it returns a tool_calls list instead of content. You execute the function and send the result back in a tool message. The model then generates its final response.
How do I get structured JSON output from the OpenAI API?
Set response_format to {"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}} to constrain output to a specific JSON Schema — guaranteed valid JSON matching your schema. For simpler cases, {"type": "json_object"} ensures valid JSON without a schema constraint. Both modes work with Chat Completions.
How do I stream OpenAI API responses?
Pass stream=True to client.chat.completions.create(). The response becomes an iterator that yields ChatCompletionChunk objects. Each chunk has choices[0].delta.content with the next token fragment. Use the context manager with client.chat.completions.stream(...) for automatic cleanup and to access the final message after iteration.
Does the OpenAI API support vision and image inputs?
Yes. Pass an image_url content block with type: "image_url" and a URL or base64-encoded data URI in the messages array. GPT-4o and GPT-4o-mini support vision. You can send multiple images per message. Use detail: "low" to reduce token cost for images where fine detail is not needed.