OpenAI APIAPI TutorialFunction Calling

OpenAI API Tutorial 2026: First Call to Production

1 min read

OpenAI’s documentation is comprehensive. It’s also scattered across six different API references, three migration guides, and a changelog that updates monthly.

Tutorials from 2024 reference deprecated models and removed parameters. You search “OpenAI streaming example” and find four different implementations —two of which still work.

This tutorial covers every major OpenAI API feature as of July 2026, in the order you should learn them, with code that runs.

No deprecated parameters. No “check the latest docs” cop-outs. Every example tested against the current API.

The OpenAI API Landscape in 2026

OpenAI currently maintains three active APIs, and knowing which one to use prevents a lot of confusion.

Chat Completions API (/v1/chat/completions): The classic. Stateless, request-response. Send messages, get a completion. Supports streaming, function calling, JSON mode, and structured outputs. This is what 90% of applications use. If you’re not sure which API to use, use this one.

Responses API (/v1/responses): Newer, stateful. Maintains conversation state server-side instead of requiring you to manage message arrays. Supports web search, file search, and computer use as built-in tools. Better for complex agent workflows where the model needs to orchestrate multiple tools across multiple turns. The tradeoff: less control over the message history, and the API is still evolving.

Agents SDK: The newest addition. A framework for building persistent AI agents with built-in guardrails, handoff between specialized agents, and tracing. More opinionated than the raw APIs —you trade flexibility for faster development of common agent patterns. Not covered in detail here; the Building AI Agents guide covers this in depth.

Current model lineup (July 2026):

ModelInput $/MOutput $/MContextBest For
GPT-5.5$5.00$30.001MMaximum capability, complex reasoning
GPT-5.4$2.50$15.001MStrong capability, better value
GPT-5.4 Mini$0.75$4.50400KEveryday tasks, good cost/quality balance
GPT-5.4 Nano$0.20$1.25128KHigh-volume simple tasks
o4-mini$1.10$4.40200KMath, logic, code puzzles (reasoning-specialized)

Authentication. Set your API key as the OPENAI_API_KEY environment variable —never hardcode it. For production key management, rotation, scoping, and virtual key architecture, see our guide to API key management.

Chat Completions API: The Foundation

Every OpenAI integration starts here.

Basic chat call —Python:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.tokspan.com/v1",
    api_key="ts-your-key-here"
)

response = client.chat.completions.create(
    model="gpt-5.5",
    messages=[
        {"role": "system", "content": "You are a software engineer. Answer with code when appropriate."},
        {"role": "user", "content": "Write a Python function to check if a string is a palindrome."}
    ],
    temperature=0.3,       # Low = deterministic, good for code
    max_tokens=500,        # Cap output length
    top_p=0.95             # Nucleus sampling —usually leave at default
)

print(response.choices[0].message.content)

Every parameter that matters:

  • model —which model to use. Use dated IDs (gpt-5.5-2025-06-15) in production, not aliases (gpt-5.5). Aliases silently upgrade to new snapshots that may change your prompt behavior.
  • messages —array of message objects with role (“system”, “user”, “assistant”) and content. System message sets behavior. User message is the request. Assistant messages are previous model responses —include them to maintain conversation context.
  • temperature —0 to 2. Use 0–0.3 for code and factual tasks. 0.7–1.0 for chat and creative writing. 1.0+ for brainstorming.
  • max_tokens —hard cap on output length. The model stops when it hits this limit, even mid-sentence. Set it generously (500–4,000) for most tasks.
  • top_p —alternative to temperature. Usually leave at default (1.0) and control randomness with temperature alone.

System messages done right. A good system message is specific, not philosophical. Bad: “You are a helpful AI assistant.” Good: “You are a Python code reviewer. For every code snippet, identify: (1) potential bugs, (2) performance issues, (3) style violations. Format your response as a bulleted list. Keep each bullet under 30 words.”

Multi-turn conversations. The API is stateless. It doesn’t remember your previous calls.

To have a conversation, you send the entire message history every time —system message + all previous user and assistant messages + the new user message. When the history approaches the model’s context limit, trim the oldest messages or summarize them. Truncation is better than an error; summarization is better than truncation.

Streaming: Real-Time Responses

Non-streaming mode: user waits 3–8 seconds, then sees the full response at once. Streaming mode: user sees words appear in real time starting at ~0.4 seconds. The UI difference is the difference between “this feels slow” and “this feels instant.”

Python streaming implementation:

stream = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "Explain recursion."}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

Node.js streaming implementation:

const stream = await client.chat.completions.create({
    model: "gpt-5.5",
    messages: [{ role: "user", content: "Explain recursion." }],
    stream: true
});

for await (const chunk of stream) {
    if (chunk.choices[0]?.delta?.content) {
        process.stdout.write(chunk.choices[0].delta.content);
    }
}

Edge cases to handle: Empty chunks (the first few chunks in a stream often have no content —the API is still processing). Connection drops (wrap the stream in a try/except, retry with the same messages if it fails mid-stream). Finish reason tracking (the last chunk contains finish_reason —check it to know whether the model stopped naturally or hit a limit).

Function Calling: Give Your LLM Tools

The model doesn’t execute code. It generates JSON that describes which function to call and with what parameters. Your code executes the function.

You send the result back. The model uses the result to generate its final response. This is the architecture behind every AI agent.

Complete weather agent example:

import json

# Step 1: Define the tool
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get current weather for a city. Returns temperature in Celsius and conditions.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name, e.g. 'Tokyo'"}
            },
            "required": ["city"]
        }
    }
}]

# Step 2: User asks a question that needs the tool
response = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
    tools=tools,
    tool_choice="auto"  # Model decides whether to use a tool
)

# Step 3: Check if model wants to call a tool
msg = response.choices[0].message
if msg.tool_calls:
    tool_call = msg.tool_calls[0]
    args = json.loads(tool_call.function.arguments)

    # Step 4: Execute the function (in reality, call a weather API)
    weather_result = get_actual_weather(args["city"])

    # Step 5: Send the result back
    messages = [
        {"role": "user", "content": "What's the weather in Tokyo?"},
        msg,  # The assistant's tool_call message
        {"role": "tool", "tool_call_id": tool_call.id, "content": str(weather_result)}
    ]

    final_response = client.chat.completions.create(
        model="gpt-5.5",
        messages=messages
    )
    print(final_response.choices[0].message.content)

Parallel function calling. Define multiple tools. The model may request several at once if they’re independent —“get weather in Tokyo AND Osaka.” Your code should handle multiple tool_calls in the response, execute them in parallel (asyncio.gather), and send all results back together.

Function calling best practices. Tool descriptions are prompts —write them clearly and include examples of when to use each tool. Constrain parameters tightly —use enums instead of free-text strings. OpenAI’s function calling guide covers edge cases like streaming tool calls and parallel execution in detail.

Make tools idempotent. When a tool execution fails, send the error message back to the model —it can often recover by trying different parameters.

For a cross-provider comparison of function calling across OpenAI, Anthropic, Google, and DeepSeek —including which features survive OpenAI-compatible translation —the tool calling comparison has the full cross-provider breakdown.

Structured Outputs: Guaranteed JSON

JSON mode (response_format={"type": "json_object"}) hints that you want JSON. The model usually complies. Structured Outputs (response_format={"type": "json_schema", ...}) guarantees it —the model’s token sampling is constrained to only produce valid JSON matching your schema.

When to use which. JSON mode: quick prototyping, internal tools, cases where you can handle occasional malformed JSON. Structured Outputs: production APIs, customer-facing features, any case where invalid JSON causes a cascade failure. OpenAI’s Structured Outputs documentation covers the full schema definition syntax and supported models.

Defining a schema —resume parser example:

response = client.chat.completions.create(
    model="gpt-5.4",  # Structured Outputs supported on GPT-5.4+
    messages=[{"role": "user", "content": f"Extract information from this resume:\n\n{resume_text}"}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "resume_extraction",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "skills": {"type": "array", "items": {"type": "string"}},
                    "years_experience": {"type": "integer"},
                    "current_role": {"type": "string"}
                },
                "required": ["name", "skills", "years_experience"]
            }
        }
    }
)

resume_data = json.loads(response.choices[0].message.content)
# Guaranteed to match your schema. No try/except json.loads needed.

Production Deployment Checklist

Environment management. API keys in a secrets vault (AWS Secrets Manager, HashiCorp Vault, Doppler), not in .env files. Rotate keys every 90 days. Use separate keys for development, staging, and production with different budget caps and model allowlists.

Error handling for production. Wrap every API call in a retry with exponential backoff and jitter. Circuit-break providers that fail consistently —stop routing to them for 30 seconds, probe, resume if healthy. Never return raw API errors to users —map them to user-friendly messages and log the details internally.

Cost monitoring. Track cost per user, per feature, per model. Set anomaly alerts at 2x normal daily spend.

The $500 surprise bill happens when nobody was watching. Daily cost summaries take 10 seconds to scan.

Rate limit management. Know your tier’s RPM and TPM limits. Read x-ratelimit-remaining-* headers on every response. Slow down at 30% remaining. Stop at 10%.

For the complete rate-limit architecture —from reactive backoff to predictive throttling —see our production rate-limit handling guide.

The alternative path. An aggregation platform handles authentication, error recovery, cost logging, and rate-limit management at the infrastructure level. You focus on your application logic.

The tradeoff is reduced control over the request path. For most teams, the time saved outweighs the control surrendered.

FAQ

What’s the difference between GPT-5.5 and o4-mini?

GPT-5.5 is a general-purpose model for chat, coding, analysis, and generation. o4-mini is a reasoning-specialized model —it thinks longer before responding, making it stronger at math, logic puzzles, and formal reasoning, but slower and more expensive per token.

Use GPT-5.5 for everyday tasks. Use o4-mini for tasks where you’d normally reach for a calculator or a formal proof.

Do I need to use the Responses API instead of Chat Completions?

Not yet. Chat Completions is stable, widely supported, and handles 90% of use cases. Responses API adds state management and built-in tools (web search, file search) but is newer and evolving.

Start with Chat Completions. Migrate to Responses API when you need its specific features.

How do I reduce my OpenAI API costs?

Use GPT-5.4 Mini ($0.75/$4.50) instead of GPT-5.5 ($5/$30) for simple tasks. Enable prompt caching —50% off cached input. Use batch API for non-urgent work —50% discount for 24-hour turnaround.

Or use an aggregation platform where volume-pooled pricing and automatic model routing reduce costs without manual model-switching. The bill-cutting tactics guide walks through each strategy.

Can I use the OpenAI SDK with non-OpenAI models?

Yes. Most providers offer OpenAI-compatible endpoints.

Change base_url and api_key. Your code stays the same. This is the single biggest advantage of the OpenAI-compatible standard —you’re not locked into one provider.

What happens when OpenAI deprecates a model I’m using?

OpenAI typically gives 1–3 months notice. Pin to dated model IDs (gpt-5.5-2025-06-15), not aliases (gpt-5.5), to control when you migrate.

Test the replacement model with your prompts before the deprecation date. Have a non-OpenAI fallback model configured so you’re not forced to migrate on OpenAI’s timeline.

The OpenAI API is the industry standard for a reason: mature SDKs, comprehensive documentation, and an ecosystem that supports it first. But 2026 is the first year that standard is showing strain —Anthropic’s native protocol, Google’s automatic function calling, and DeepSeek’s pricing pressure are each pulling developers toward features that do not survive translation through /v1/chat/completions. The question worth tracking: will OpenAI’s Agents SDK become the next industry standard that re-unifies the ecosystem, or will it accelerate the fragmentation by introducing capabilities only available on OpenAI’s own infrastructure?

Start coding —Master OpenAI’s API your way. Then add Claude, Gemini, and DeepSeek through the same SDK when you are ready —because the only safe bet in 2026 is code that runs on every provider.