CoreMesh

How to Use the OpenAI API in Python: Examples You Can Run

Install the official SDK, set your API key from the environment, make a first request, and handle errors in Python, with code you can copy.

How to Use the OpenAI API in Python: Examples You Can Run

To call the OpenAI API from Python, install the official openai package, put your key in the OPENAI_API_KEY environment variable, and call client.responses.create(...). The SDK reads the key from the environment by default, so the client needs no arguments.

The SDK requires Python 3.10 or newer. It has a sync client (OpenAI) and an async client (AsyncOpenAI), and it raises typed exceptions you can catch. The sections below cover install, the key, a first request, streaming, async, errors, and the usual gotchas.

Install the OpenAI Python library#

The official package is openai on PyPI. The openai-python repository says it works with any Python 3.10+ application.

bash
pip install openai

I'd install it into a virtual environment per project so the SDK version doesn't drift between apps. The package is generated from OpenAI's OpenAPI specification and ships type definitions for request params and response fields. Your editor can autocomplete most of what you write.

If you want the optional aiohttp-based async HTTP backend, the README documents pip install openai[aiohttp]. You don't need it to get started.

Set the OpenAI API key in Python#

Create an API key in the OpenAI platform, then keep it out of your source code. The README recommends using python-dotenv and adding this line to a .env file, so the key isn't stored in source control:

text
OPENAI_API_KEY="My API Key"

Replace the placeholder with your real key, and add .env to .gitignore.

There are two ways to pass the key to the client:

python
import os
from openai import OpenAI

# 1. Implicit: the client reads OPENAI_API_KEY itself
client = OpenAI()

# 2. Explicit: same result, just spelled out
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

The README marks the explicit form as "the default and can be omitted." Prefer the first. Hardcoding api_key="sk-..." works, but that's how keys end up in Git history.

This small script checks that the variable is visible to your Python process without printing the secret:

python
import os

key = os.environ.get("OPENAI_API_KEY")
if key:
    print(f"OPENAI_API_KEY is set ({len(key)} characters)")
else:
    print("OPENAI_API_KEY is not set in this process")

If it says "not set" and you're sure you set it, see the gotchas section below.

Make your first OpenAI API call in Python#

The README calls the Responses API the primary way to interact with OpenAI models. This is the smallest version that works:

python
from openai import OpenAI

client = OpenAI()

response = client.responses.create(
    model="gpt-5.5",
    instructions="You are a coding assistant that talks like a pirate.",
    input="How do I check if a Python object is an instance of a class?",
)

print(response.output_text)

Three things to know:

  • model is the model name. The README example uses gpt-5.5, and the quickstart uses a different name. Model names change, so check the OpenAI quickstart and the models documentation for what your account can use.
  • instructions sets the high-level behavior, and input is the user's request.
  • response.output_text is the plain text of the answer.

Chat Completions, if you already use it#

The README describes Chat Completions as the previous standard, supported indefinitely. If your code base already uses it, there's no pressure to rewrite:

python
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": "How do I check if a Python object is an instance of a class?"},
    ],
)

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

For new code I'd start with the Responses API, since that's what the docs lead with.

Sending images or files#

The quickstart shows the same responses.create call taking a list of input items. A user message can mix input_text with an input_image (via image_url) or an input_file (via file_url or an uploaded file_id). Uploads use client.files.create(file=open("draconomicon.pdf", "rb"), purpose="user_data").

Streaming responses from the OpenAI API#

The README excerpt I worked from doesn't include a streaming example for the Responses API, so I won't invent the parameters here. Check the streaming section of the OpenAI docs for the current call.

The README does cover two streaming-related facts you should plan around:

  • Streaming responses come back as a Stream (or AsyncStream for the async client).
  • Stream consumption is not automatically retried, because replaying a request could duplicate output you've already delivered to your application.

If you want token-by-token output over a persistent connection, the Realtime API is documented in the README. It uses WebSockets, supports text and audio, and the SDK uses the websockets library under the hood. This text-only example prints deltas as they arrive:

python
import asyncio
from openai import AsyncOpenAI

async def main():
    client = AsyncOpenAI()

    async with client.realtime.connect(model="gpt-realtime-2") as connection:
        await connection.session.update(
            session={"type": "realtime", "output_modalities": ["text"]}
        )

        await connection.conversation.item.create(
            item={
                "type": "message",
                "role": "user",
                "content": [{"type": "input_text", "text": "Say hello!"}],
            }
        )
        await connection.response.create()

        async for event in connection:
            if event.type == "response.output_text.delta":
                print(event.delta, flush=True, end="")
            elif event.type == "response.output_text.done":
                print()
            elif event.type == "response.done":
                break

asyncio.run(main())

You send events (update the session, create an item, request a response) and read server events back. Break out of the loop on response.done.

Async usage#

Import AsyncOpenAI instead of OpenAI and await each call. The README says functionality is otherwise identical.

python
import asyncio
from openai import AsyncOpenAI

client = AsyncOpenAI()

async def main() -> None:
    response = await client.responses.create(
        model="gpt-5.5",
        input="Explain disestablishmentarianism to a smart five year old.",
    )
    print(response.output_text)

asyncio.run(main())

Use the async client inside web servers and anything already running an event loop. A sync client blocks the loop while it waits.

Handling OpenAI API errors in Python#

The SDK raises typed exceptions, and all of them inherit from openai.APIError:

  • openai.APIConnectionError (and subclasses) when the library can't reach the API, for example a network problem or timeout.
  • openai.APIStatusError (and subclasses) when the API returns a 4xx or 5xx. It carries status_code and response.

The status-code mapping from the README:

Status Exception
400 BadRequestError
401 AuthenticationError
403 PermissionDeniedError
404 NotFoundError
422 UnprocessableEntityError
429 RateLimitError
>=500 InternalServerError
N/A (no response) APIConnectionError

Catch the specific ones first and the general ones last:

python
import openai
from openai import OpenAI

client = OpenAI()

try:
    response = client.responses.create(model="gpt-5.5", input="Hello")
    print(response.output_text)
except openai.APIConnectionError as e:
    print("The server could not be reached")
    print(e.__cause__)  # underlying exception, likely from the HTTP layer
except openai.RateLimitError:
    print("A 429 was received; back off a bit.")
except openai.APIStatusError as e:
    print("Another non-200-range status code was received")
    print(e.status_code)
    print(e.response)

Order matters because RateLimitError is a kind of APIStatusError. Put the general class first and the specific branch never runs.

While reading a stream, read timeouts raise APITimeoutError and other HTTP request failures raise APIConnectionError. Catch these SDK exceptions rather than raw HTTP library errors. The original exception is on __cause__.

A quick way to turn a status code into a plain-language next step, runnable anywhere:

python
HINTS = {
    400: ("BadRequestError", "fix the request parameters"),
    401: ("AuthenticationError", "check the API key"),
    403: ("PermissionDeniedError", "check access for this key"),
    404: ("NotFoundError", "check the model name or resource ID"),
    422: ("UnprocessableEntityError", "fix the request body"),
    429: ("RateLimitError", "back off and retry later"),
}

def explain(status):
    if status >= 500:
        return ("InternalServerError", "server side; retry later")
    return HINTS.get(status, ("APIStatusError", "inspect e.response"))

for code in (400, 401, 404, 429, 503):
    name, hint = explain(code)
    print(code, name, "->", hint)

Azure OpenAI from Python#

For Azure OpenAI, use the AzureOpenAI class instead of OpenAI. The README example:

python
from openai import AzureOpenAI

# gets the API key from the AZURE_OPENAI_API_KEY environment variable
client = AzureOpenAI(
    api_version="2023-07-01-preview",
    azure_endpoint="https://example-endpoint.openai.azure.com",
)

completion = client.chat.completions.create(
    model="deployment-name",  # your Azure deployment name
    messages=[{"role": "user", "content": "How do I output all files in a directory using Python?"}],
)
print(completion.to_json())

Here model is your deployment name. The client also reads AZURE_OPENAI_ENDPOINT, OPENAI_API_VERSION and AZURE_OPENAI_AD_TOKEN from the environment. The README warns that Azure's API shape differs from the core API, so the static types won't always be correct. Check the current api_version in Microsoft's docs before copying the one above.

Common mistakes and gotchas#

  • Key not found. An export in one terminal doesn't reach another terminal or an IDE run configuration. Run the check script above from the same process that makes the call. A .env file does nothing unless something like python-dotenv loads it.
  • 401 AuthenticationError. The key is missing, mistyped, or revoked. Print its length, not its value, and create a new key if in doubt.
  • Wrong exception order. Catch RateLimitError before APIStatusError.
  • Key in Git. If you pasted a key into code and committed it, treat it as leaked and replace it.
  • Mixing Azure and OpenAI settings. Azure uses AZURE_OPENAI_API_KEY and a deployment name, not a plain model name.
  • Retrying streams blindly. The SDK doesn't retry stream consumption, so decide how your app handles a half-delivered answer.
  • Cost and free use. The source I used states no prices or free-tier terms. Check the OpenAI pricing page and your account's usage dashboard before running loops.

Quick reference#

  • [ ] Python 3.10 or newer
  • [ ] pip install openai in a virtual environment
  • [ ] Key in OPENAI_API_KEY (or a .env loaded with python-dotenv), never in source
  • [ ] client = OpenAI(), then client.responses.create(model=..., input=...)
  • [ ] Read the answer from response.output_text
  • [ ] Use AsyncOpenAI with await in async code
  • [ ] Catch APIConnectionError, RateLimitError, then APIStatusError
  • [ ] Check the current model names and pricing on the OpenAI platform
  • [ ] Package details live on PyPI

Quick answers

How do I set the OpenAI API key in Python?

Set the OPENAI_API_KEY environment variable and create the client with OpenAI(), which reads it automatically. You can also pass api_key=os.environ.get("OPENAI_API_KEY") explicitly. The README recommends python-dotenv with a .env file so the key stays out of source control.

Why is my OpenAI API key not working in Python?

A 401 raises AuthenticationError, which usually means the key is missing, wrong, or revoked. Confirm the variable is visible to the same Python process that makes the call, since a shell export doesn't reach other terminals or IDE runs.

Which OpenAI Python class should I use for the first request?

Use OpenAI().responses.create(...) and read response.output_text. The README calls the Responses API the primary API, and Chat Completions remains supported indefinitely.

Can I use the OpenAI Python SDK with Azure?

Yes. Use the AzureOpenAI class with azure_endpoint and api_version, and pass your deployment name as model. It reads AZURE_OPENAI_API_KEY from the environment.

Did this solve it?

One tap. No account.

Saved you an hour? Send a tip.

USDC or ETH on Base. Keeps the notes free and the examples running.

Base
0x9dFD2Ee86182f92464b50809C6702B999a0Cd54f
Open in wallet · 5 USDC

On a computer? Scan the code with your phone wallet, or copy the address.

USDC or ETH on Base works best. Other tokens on Base, Ethereum or Arbitrum also reach this address. Tips are optional and unlock nothing; every guide stays free.

Discussion

Start the discussion

`code` and ``` blocks work

No account needed. Comments are read before they show up, usually the same day. Your email is never asked for.

Indra Wijaya

Builds and runs AI agents, bots and content pipelines, and writes down what works and what broke.

About · Email · RSS

Keep reading

New notes, no spam.

One post at a time, only when there's something worth reading. Follow in any feed reader.

Subscribe via RSS