mrkeyoor.com_
Wed 05 Aug 05:04 UTC
PyPIAI / MLupdated 05 Aug 2026

openai

openai is the official Python SDK for the OpenAI REST API, generated from the OpenAPI specification with Stainless. It gives you synchronous and asynchronous clients built on httpx, typed request params (TypedDicts) and typed responses (Pydantic models), and covers the Responses API, Chat Completions, streaming, the Realtime API over WebSockets, file uploads, fine-tuning, and webhook verification. Retries, timeouts, and pagination are handled by the client, and it requires Python 3.10 or newer.

Verdict

If you call OpenAI from Python, use the official SDK; the typed clients, retries, and streaming support are worth it. Just do not expect snippets you found last year to run unchanged, and pin your version.

API stability3/5The 2023 v1 rewrite invalidated all earlier code, and the platform keeps moving weight from Chat Completions to Responses. Within the 2.x line the client API itself has been steady.
Docs4/5The README is long and example-dense, with a full api.md reference in the repo. You still cross-reference platform.openai.com for endpoint semantics, so answers live in two places.
Maintenance5/5Generated from the OpenAPI spec and released nearly continuously by OpenAI; the repo was pushed the day before this review.
Ecosystem5/5Around 108 million weekly downloads and the reference SDK that nearly every Python AI framework and tool integrates against.

Use it if

  • You call OpenAI models from Python and want typed requests, automatic retries, and pagination instead of hand-rolled HTTP
  • You need streaming responses or the Realtime API, which the SDK wires up over SSE and WebSockets for you
  • You receive OpenAI webhooks and want signature verification via client.webhooks.unwrap() rather than doing HMAC checks yourself
Skip it if

Setup reality

pip install openai, set OPENAI_API_KEY, and the basic call works. The rough edges are legacy and defaults: an enormous amount of pre-2023 sample code (openai.ChatCompletion.create) no longer runs, so most debugging sessions for newcomers are really migration sessions. The default timeout is a surprising 10 minutes and failed requests are retried twice automatically, which can hide flakiness or double your latency if you do not tune max_retries and timeout. Async with aiohttp and the httpx2 mode are separate optional extras.

Patterns

Generate text with the Responses APIbasic-response

from openai import OpenAI

client = OpenAI()  # reads OPENAI_API_KEY

response = client.responses.create(
    model="gpt-5.5",
    instructions="You are a terse coding assistant.",
    input="How do I reverse a list in Python?",
)
print(response.output_text)

Responses is the primary API now; output_text is the convenience accessor for the final text.

Use the Chat Completions APIchat-completions

from openai import OpenAI

client = OpenAI()

completion = client.chat.completions.create(
    model="gpt-5.5",
    messages=[
        {"role": "developer", "content": "Talk like a pirate."},
        {"role": "user", "content": "Explain generators."},
    ],
)
print(completion.choices[0].message.content)

Chat Completions remains supported indefinitely, but new platform features tend to land on Responses first.

Stream a response as it generatesstream-response

from openai import OpenAI

client = OpenAI()

stream = client.responses.create(
    model="gpt-5.5",
    input="Write a one-sentence bedtime story about a unicorn.",
    stream=True,
)
for event in stream:
    print(event)

Streaming yields typed SSE events, not raw text deltas; filter on event type before printing to users.

Call the API asynchronouslyasync-client

import asyncio
from openai import AsyncOpenAI

client = AsyncOpenAI()

async def main() -> None:
    response = await client.responses.create(
        model="gpt-5.5", input="Explain asyncio in one paragraph."
    )
    print(response.output_text)

asyncio.run(main())

The async client mirrors the sync API exactly; install the aiohttp extra and pass DefaultAioHttpClient for higher concurrency.

Send an image to the modelvision-image-input

import base64
from openai import OpenAI

client = OpenAI()

with open("photo.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode("utf-8")

response = client.responses.create(
    model="gpt-5.5",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": "What is in this image?"},
            {"type": "input_image", "image_url": f"data:image/png;base64,{b64}"},
        ],
    }],
)

image_url takes either an https URL or a data URL; base64 payloads count against request size limits.

Handle API errors by typeerror-handling

import openai
from openai import OpenAI

client = OpenAI()

try:
    client.responses.create(model="gpt-5.5", input="hi")
except openai.APIConnectionError as e:
    print("network problem:", e.__cause__)
except openai.RateLimitError:
    print("429: back off")
except openai.APIStatusError as e:
    print(e.status_code, e.response)

All errors inherit from openai.APIError; catch APIStatusError to read the request_id of a failed call.

Configure or disable automatic retriesconfigure-retries

from openai import OpenAI

client = OpenAI(max_retries=0)  # default is 2

# or per request:
client.with_options(max_retries=5).responses.create(
    model="gpt-5.5", input="hello"
)

Connection errors, 408, 409, 429, and 5xx are retried with exponential backoff by default; timeouts get retried too.

Set request timeoutsconfigure-timeout

import httpx
from openai import OpenAI

client = OpenAI(
    timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
)

# or per request:
client.with_options(timeout=5.0).responses.create(
    model="gpt-5.5", input="quick answer please"
)

The default timeout is 10 minutes, which is almost never what a web request path wants.

Iterate a paginated list endpointauto-pagination

from openai import OpenAI

client = OpenAI()

all_jobs = []
for job in client.fine_tuning.jobs.list(limit=20):
    all_jobs.append(job)  # pages are fetched as needed

Iterating the list result fetches successive pages automatically; use .has_next_page() for manual control.

Upload a filefile-upload

from pathlib import Path
from openai import OpenAI

client = OpenAI()

client.files.create(
    file=Path("input.jsonl"),
    purpose="fine-tune",
)

You can pass bytes, a PathLike, or a (filename, contents, media type) tuple; the async client reads files without blocking.

Verify and parse an OpenAI webhookverify-webhook

from openai import OpenAI
from flask import Flask, request

app = Flask(__name__)
client = OpenAI()  # uses OPENAI_WEBHOOK_SECRET env var

@app.route("/webhook", methods=["POST"])
def webhook():
    body = request.get_data(as_text=True)
    try:
        event = client.webhooks.unwrap(body, request.headers)
        return "ok"
    except Exception:
        return "Invalid signature", 400

Pass the raw body string, not parsed JSON; unwrap() verifies the signature before parsing and raises on mismatch.

Read response headers and request IDsraw-response-headers

from openai import OpenAI

client = OpenAI()

response = client.chat.completions.with_raw_response.create(
    messages=[{"role": "user", "content": "Say this is a test"}],
    model="gpt-5.5",
)
print(response.headers.get("x-request-id"))
completion = response.parse()

Every parsed object also exposes _request_id; log it when reporting problems to OpenAI support.

Alternatives

PackageRegistryPick it when
anthropicPyPIYou are calling Claude models; the SDK has a near-identical shape so the switch is mechanical
litellmPyPIYou need one calling convention across many providers with routing and fallbacks