n4nAI

How to call GPT-4o via REST API using Python requests

Step-by-step guide to calling GPT-4o via REST API using Python requests, from API key setup to parsing streaming responses and handling errors.

n4n Team3 min read689 words

Audio narration

Coming soon — every post will get a voice note here.

Calling the python requests gpt-4o rest api is the lowest-overhead way to integrate OpenAI’s flagship model into a backend service without dragging in a heavy SDK. You get full control over headers, timeouts, and retries, and you can point the same code at any OpenAI-compatible gateway.

Step 1: Get an API key and configure your environment

Create an API key in the OpenAI dashboard under “API keys”. Export it as an environment variable so it never touches your source tree:

export OPENAI_API_KEY="sk-..."

In Python, read it and fail fast if absent:

import os

API_KEY = os.environ.get("OPENAI_API_KEY")
if not API_KEY:
    raise RuntimeError("OPENAI_API_KEY environment variable is not set")

If you run this in a container, inject the secret via the orchestrator’s secret store, not a baked image layer.

Step 2: Understand the endpoint and request shape

The chat completions endpoint is https://api.openai.com/v1/chat/completions. It accepts a JSON body with model, messages, and optional sampling parameters. The python requests gpt-4o rest api interaction is a single HTTP POST.

Headers must carry the bearer token and declare JSON:

import requests

URL = "https://api.openai.com/v1/chat/completions"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

Request payload reference

A minimal valid body looks like this:

{
  "model": "gpt-4o",
  "messages": [
    {"role": "system", "content": "You are a concise backend engineer."},
    {"role": "user", "content": "Explain idempotency keys in one sentence."}
  ],
  "temperature": 0.1,
  "max_tokens": 120
}

temperature controls randomness; max_tokens caps the generated reply length, not the context window. GPT-4o supports a 128k token context as documented by OpenAI.

Step 3: Send a minimal chat completion

Build the payload in Python and post it. Always set an explicit timeout—the default blocks forever, which will quietly stall your worker pool during provider brownouts.

payload = {
    "model": "gpt-4o",
    "messages": [
        {"role": "system", "content": "You are a terse senior engineer."},
        {"role": "user", "content": "Write a one-line Python function to flatten a list."},
    ],
    "temperature": 0.2,
    "max_tokens": 200,
}

resp = requests.post(URL, headers=HEADERS, json=payload, timeout=30)

Using json=payload lets requests serialize and set Content-Type automatically. If you pre-serialize with json.dumps, you must keep the header manual.

Step 4: Parse the response

A 200 response returns a JSON object with a choices array. Extract the assistant message and the finish reason:

resp.raise_for_status()
data = resp.json()

content = data["choices"][0]["message"]["content"]
finish_reason = data["choices"][0]["finish_reason"]
print(content)
print("finish_reason:", finish_reason)

Capture token usage for metering:

usage = data.get("usage", {})
print(f"prompt_tokens={usage.get('prompt_tokens')} completion_tokens={usage.get('completion_tokens')}")

If you later route through a gateway, the usage shape stays identical.

Step 5: Handle errors and rate limits

OpenAI returns 429 on rate limits and 5xx on upstream failures. Wrap the call in a retry loop with exponential backoff; never retry 4xx except 429.

import time

def call_gpt4o(payload, max_retries=3):
    for attempt in range(max_retries):
        try:
            r = requests.post(URL, headers=HEADERS, json=payload, timeout=30)
            if r.status_code == 429:
                time.sleep(2 ** attempt)
                continue
            r.raise_for_status()
            return r.json()
        except requests.HTTPError as e:
            if r.status_code >= 500:
                time.sleep(2 ** attempt)
                continue
            raise
    raise RuntimeError("Exhausted retries calling GPT-4o")

Use a Session for throughput

If your service makes many calls, reuse a requests.Session to keep TCP/TLS connections alive:

session = requests.Session()
session.headers.update(HEADERS)

def call_gpt4o_session(payload):
    r = session.post(URL, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()

This cuts handshake overhead significantly under load.

Step 6: Stream tokens for responsive UX

Non-streaming calls block until the full completion is ready. For chat interfaces, enable streaming. Set "stream": True and iterate the response as Server-Sent Events.

payload["stream"] = True
with requests.post(URL, headers=HEADERS, json=payload, stream=True, timeout=30) as r:
    r.raise_for_status()
    for line in r.iter_lines():
        if not line:
            continue
        if line.startswith(b"data: "):
            chunk = line[len(b"data: "):]
            if chunk == b"[DONE]":
                break
            delta = json.loads(chunk)
            token = delta["choices"][0]["delta"].get("content", "")
            print(token, end="", flush=True)

requests has no SSE parser, so you decode lines manually. For async services, httpx.AsyncClient offers the same REST contract with native streaming.

Step 7: Verify the integration end to end

Write a script that asserts a successful round trip. Success means HTTP 200, a non-empty message, and a sane finish_reason.

def test_call():
    p = {
        "model": "gpt-4o",
        "messages": [{"role": "user", "content": "Say 'pong'."}],
        "max_tokens": 10,
    }
    data = call_gpt4o(p)
    text = data["choices"][0]["message"]["content"].strip().lower()
    assert text == "pong", f"unexpected reply: {text}"
    assert data["choices"][0]["finish_reason"] in ("stop", "length")
    print("OK")

test_call()

Run python main.py. If it prints OK, your python requests gpt-4o rest api wiring is correct.

You can also verify from the shell before writing Python:

curl -s https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"Say pong"}],"max_tokens":5}' | head

In CI, mock the endpoint with responses or respx to avoid spending tokens on every run.

Step 8: Swap to an OpenAI-compatible gateway

If you want automatic fallback when a provider is rate-limited or degraded, or access to 240+ models behind one endpoint, an OpenRouter-class gateway like n4n.ai exposes the same /v1/chat/completions shape. Change only the base URL and key:

URL = "https://api.n4n.ai/v1/chat/completions"
HEADERS = {"Authorization": f"Bearer {GATEWAY_KEY}", "Content-Type": "application/json"}

The payload stays byte-for-byte compatible because the API is OpenAI-compatible. You can forward provider cache-control hints via extra headers if the gateway honors them.

Gotchas that will bite you

  • Missing Content-Type: requests sets it with json=, but manual data=json.dumps(...) without the header yields a 400.
  • Silent truncation: max_tokens limits the reply only. Set it high enough for your task.
  • Model string casing: gpt-4o is lowercase with a hyphen. GPT-4O or gpt-4O fail.
  • TLS interception: never set verify=False in production to bypass a proxy. Install the corporate CA bundle correctly.
  • Timeouts on stream: pass timeout to the post, but also handle slow token delivery with a read timeout if your client supports it.

Why raw requests instead of the SDK

The official openai package abstracts auth, retries, and streaming behind a client. That is convenient until you need to inspect exact bytes for a proxy debug or inject custom metrics. The raw python requests gpt-4o rest api path shows every header and body, and avoids SDK version churn when the vendor changes method signatures.

Keep the functions above in a client.py module and import call_gpt4o where needed. That single seam lets you later add caching, structured logging, or provider routing without touching call sites.

Tagspythonrequestsgpt-4orest-api

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All python raw rest calls (requests/httpx) posts →