Your First LLM API Call
Make a working call to Claude in Python, then the same call with the OpenAI SDK, plus streaming, JSON output, real costs, and the first errors you will hit.

Every LLM product starts with one HTTPS request. This guide takes you from no account to a working Python call against Claude, then the same call on the OpenAI SDK, streaming, JSON output, what the call costs, and the first errors you will meet. For the concepts behind the call, read the LLM mental model for engineers .
The request lifecycle
Step 1: Get an API key
Create a key in the Claude Console at platform.claude.com
(Anthropic) or at platform.openai.com
(OpenAI). New Anthropic accounts get a small amount of free credit to test with. To try models before creating any account, use the free options on our Playgrounds page
. Export the key as an environment variable: export ANTHROPIC_API_KEY="sk-ant-...". Never paste it into code, and never commit it to Git - see Protect your accounts
.
Step 2: Install the SDK
An SDK is the official client library. It handles auth headers, retries, and typed responses for you.
pip install anthropic # Anthropic
pip install openai # OpenAIStep 3: A minimal call to Claude
The current Sonnet-tier model ID is claude-sonnet-5. max_tokens is required and caps the output length. The client reads ANTHROPIC_API_KEY from the environment.
import anthropic
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-sonnet-5",
max_tokens=200,
messages=[
{"role": "user", "content": "Explain what an API key is in one sentence."}
],
)
for block in message.content:
if block.type == "text":
print(block.text)The loop matters: message.content is a list of typed blocks, not a string. On claude-sonnet-5 a reasoning block can precede the text block, so always check block.type.
The same call with the OpenAI SDK
OpenAI’s current interface is the Responses API. It takes a single input string and offers an output_text shortcut.
from openai import OpenAI
client = OpenAI() # reads OPENAI_API_KEY
response = client.responses.create(
model="gpt-5.5",
input="Explain what an API key is in one sentence.",
)
print(response.output_text)Same lifecycle, different shapes:
| Anthropic | OpenAI | |
|---|---|---|
| Env var | ANTHROPIC_API_KEY | OPENAI_API_KEY |
| Call | client.messages.create(...) | client.responses.create(...) |
| Model ID | claude-sonnet-5 | gpt-5.5 |
| Output cap | max_tokens required | optional |
| Read text | loop over content blocks | response.output_text |
Streaming
Streaming prints tokens as they arrive instead of waiting for the full response. Use it for anything user-facing, and for any long output.
with client.messages.stream(
model="claude-sonnet-5",
max_tokens=1000,
messages=[{"role": "user", "content": "Explain rate limiting in three short paragraphs."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message() # full message, incl. usageStructured output: get JSON back
Do not parse prose with regexes. Define a Pydantic model and use client.messages.parse (reusing the client from Step 3); the API constrains the output to your schema and the SDK validates it.
from pydantic import BaseModel
class Contact(BaseModel):
name: str
email: str
demo_requested: bool
response = client.messages.parse(
model="claude-sonnet-5",
max_tokens=500,
messages=[{
"role": "user",
"content": "Extract the contact: Jane Doe (jane@example.com) asked for a demo.",
}],
output_format=Contact,
)
contact = response.parsed_output # a validated Contact instance
print(contact.name, contact.demo_requested)What the response contains
id: unique message ID. Log it; support teams trace requests with it.model: the model that actually answered.content: list of typed blocks (text,thinking,tool_use). Filter byblock.type.stop_reason: why generation ended.end_turnmeans finished naturally.max_tokensmeans your cap truncated the answer; raise it and retry.usage:input_tokensandoutput_tokens. This is the billing meter; read it after every call.
What this call costs
A token is a short chunk of text, roughly 4 English characters. Anthropic prices claude-sonnet-5 at about 1.85 EUR ($2) per million input tokens and 9.20 EUR ($10) per million output tokens until 2026-08-31, then about 2.75 EUR ($3) and 13.80 EUR ($15). EUR figures assume $1 = 0.92 EUR; billing itself is in USD. The Step 3 call sends about 20 input tokens and returns about 60 output tokens. That is (20 x 2 + 60 x 10) / 1,000,000 = $0.00064, roughly 0.06 euro cents today, and roughly 0.09 euro cents at the standard price. One million such calls cost about 590 EUR today and about 880 EUR from September. Cheap per call, real at scale - set a budget cap before you ship anything, as covered in Set spending limits before you ship
.
The first errors you will hit
| What it means | Fix | |
|---|---|---|
| 401 authentication_error | Key missing, wrong, or revoked | Check the env var name and value |
| 404 not_found_error | Model ID typo | Copy the exact ID from the docs |
| 429 rate_limit_error | Too many requests or tokens | Wait for retry-after, then retry |
| 400 invalid_request_error | Bad parameter | Read the error message; it names the field |
Three details save you an afternoon. First, the SDK raises typed exceptions (anthropic.AuthenticationError, anthropic.RateLimitError, anthropic.NotFoundError), so catch those instead of string-matching messages. Second, the SDK already retries 429 and 5xx errors twice with backoff before you ever see them. Third, claude-sonnet-5 rejects a non-default temperature with a 400; leave sampling parameters out entirely (see temperature and sampling
). When an error still stumps you, work through How to read an error message
.
Further reading
- The LLM mental model for engineers : the concepts behind the call you made here
- How to read an error message : a repeatable method for the 400s and 500s ahead
- Set spending limits before you ship : budget caps and alerts before real traffic
- Claude and the Anthropic API : the platform behind the first example
- OpenAI API : the platform behind the second example
- Anthropic quickstart : the official first-call guide with more languages
- OpenAI quickstart : the official Responses API starting point