Lesson 10 of 16 · Level 3: Advanced
How to Use an AI API with Python: From Your First Call to Processing Thousands of Texts
- ⏱ 14 min read
- ❓ 4 review questions
- ✍️ Exercise with solution
- 📥 Downloadable template
In this lesson
- Understand what an AI model's API is, how it's billed and when it makes sense to use it.
- Make your first call from Python and store your key securely.
- Keep a conversation going with history from your own program.
- Process hundreds of texts from a CSV automatically while controlling errors and cost.
- Measure the quality of an automated process before you trust it.
This is the file the classify.py script in this lesson expects. Save it in the same folder as the script.
- customer-reviews.csv · 20 customer reviews to classify with the API
Chat apps are perfect for one task at a time. But to classify 2,000 customer comments or extract data from 500 invoices, copy and paste stops working. That's what language model APIs are for: using AI from your own code to process large volumes automatically.
This lesson uses Python. If you've never programmed, read it to understand how it works and come back after our Python for data analysis lesson, which covers the basics you'll need.
What an API is and how it's billed
An API (application programming interface) is a doorway that lets one program talk to another. Instead of typing into a chat window, your program sends the message over the internet to the provider (Anthropic, OpenAI, Google and others), the model processes it and the answer comes back to your program as data.
- Use
- Manual conversation.
- Price
- Free or a monthly subscription.
- Volume
- One task at a time.
- Best for
- Daily work, varied tasks.
- Use
- Your program sends and receives the messages.
- Price
- Pay as you go, per token processed.
- Volume
- Thousands of automated tasks.
- Best for
- Repetitive processes, integrations, products.
Remember from lesson 2 that models work in tokens. With an API you pay for the tokens you send (input) and the tokens the model generates (output), which usually cost several times more. More powerful models cost more; smaller ones are much cheaper and faster.
Setup: account, key and library
- Create a developer account in the provider's console and add a payment method. This lesson uses the Claude API (Anthropic); OpenAI's and Google's work similarly.
- Set a monthly spending limit: your safety net if a program loops.
- Generate an API key. Treat it like a password: anyone who has it can spend your money.
- Install the official library in your virtual environment:
pip install anthropic
Store the key in an environment variable
Never write the key into your code: it would end up on GitHub or in a screenshot. Store it in an environment variable, which the library reads automatically:
# Windows (PowerShell), for the current session
$env:ANTHROPIC_API_KEY="your-key-here"
# macOS and Linux
export ANTHROPIC_API_KEY="your-key-here"
Revoke it in the console, create a new one and check recent usage. If you use Git, add files with keys, such as .env, to .gitignore.
Your first call
# first_message.py
import anthropic
client = anthropic.Anthropic() # reads the key from ANTHROPIC_API_KEY
response = client.messages.create(
model="claude-sonnet-5-5", # check the current models in the docs
max_tokens=500,
system="You are an assistant who answers briefly and clearly.",
messages=[
{"role": "user", "content": "Explain what an API is in 3 sentences."}
],
)
print(response.content[0].text)
print("Tokens:", response.usage.input_tokens, "input,",
response.usage.output_tokens, "output")
Expected result: three sentences explaining what an API is and, below them, a line with that call's input and output tokens. If you get an authentication error instead, the environment variable isn't set in the terminal where you're running the script.
The key parameters:
model: in November 2026,claude-sonnet-5-5is the current Sonnet andclaude-haiku-5-5the most economical option. Names change with new versions; check the documentation.max_tokens: the most tokens it may generate, which caps length and cost.system: permanent instructions, like those of the custom assistant in lesson 8.messages: the conversation, each message with its role (userorassistant).
The text comes back in response.content[0].text and the usage in response.usage, so you can price every call.
OpenAI (pip install openai) and Google (pip install google-genai) follow the same logic with a few different parameter names. Everything else in this lesson applies unchanged.
1. Where should you store your API key?
The key unlocks your paid account. If it's in the code, it leaks the moment you share the file.
A conversation with memory
The API doesn't remember anything between calls: each one is independent. To keep a conversation going, your program has to send the full history every time. That's how every chat app works under the hood:
# chat.py
import anthropic
client = anthropic.Anthropic()
history = []
while True:
question = input("You: ").strip()
if question.lower() in ("quit", "exit", ""):
break
history.append({"role": "user", "content": question})
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=800,
system="You are a personal finance tutor. Answer with U.S. examples.",
messages=history,
)
text = response.content[0].text
history.append({"role": "assistant", "content": text})
print(f"\nAI: {text}\n")
Notice the consequence: every new message resends the whole conversation, so long conversations use more and more input tokens. It's the same "context window" from lesson 2, now with a visible price tag.
Batch processing: classifying a whole CSV
This is the use case with the biggest return. We start with customer-reviews.csv, which has two columns, id and review, and we want to add a sentiment, a topic and a summary to each row. We combine what you saw in lesson 5 (JSON outputs) with file handling and error handling:
# classify.py
import csv
import json
import time
import anthropic
MODEL = "claude-sonnet-5-5"
TOPICS = {"Price", "Service", "Shipping", "Quality", "Other"}
client = anthropic.Anthropic(max_retries=3) # retries only on temporary errors
INSTRUCTIONS = """You classify customer reviews for an online store.
Reply ONLY with valid JSON, no extra text, in this shape:
{"sentiment": "Positive|Negative|Mixed", "topic": "Price|Service|Shipping|Quality|Other", "summary": "12 words max"}"""
def classify(review):
response = client.messages.create(
model=MODEL,
max_tokens=200,
system=INSTRUCTIONS,
messages=[{"role": "user", "content": f"<review>{review}</review>"}],
)
text = response.content[0].text.strip()
# In case the model wraps the JSON in a code block
text = text.removeprefix("```json").removeprefix("```").removesuffix("```").strip()
data = json.loads(text)
if data.get("topic") not in TOPICS: # validate: never trust blindly
data["topic"] = "REVIEW"
usage = response.usage.input_tokens + response.usage.output_tokens
return data, usage
def main():
with open("customer-reviews.csv", newline="", encoding="utf-8") as f:
rows = list(csv.DictReader(f))
results, tokens = [], 0
for i, row in enumerate(rows, start=1):
try:
data, usage = classify(row["review"])
tokens += usage
except json.JSONDecodeError:
data = {"sentiment": "REVIEW", "topic": "REVIEW", "summary": "Invalid response"}
except anthropic.APIError as e:
print(f"Row {i}: API error ({e.__class__.__name__}), flagged for review")
data = {"sentiment": "REVIEW", "topic": "REVIEW", "summary": ""}
results.append({**row, **data})
print(f"{i}/{len(rows)} · {data['topic']}")
time.sleep(0.5) # short pause so you don't hit rate limits
with open("reviews_classified.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=list(results[0].keys()))
writer.writeheader()
writer.writerows(results)
print(f"Done: {len(results)} reviews · {tokens} tokens used")
if __name__ == "__main__":
main()
Expected result: a file called reviews_classified.csv with the original columns plus sentiment, topic and summary, and a final line reading "Done: 20 reviews" followed by the token count. A typical row:
4,The bag arrived torn but they replaced it fast,Mixed,Service,Damaged bag replaced quickly by the store
The design choices that make the script reliable
- Exact format and closed categories, so you can analyze the output in Excel or pandas.
- Validation: a topic outside the list is flagged "REVIEW," never accepted.
- Handled errors: invalid JSON or a connection failure flags the row instead of stopping the run.
- Retries and pauses to ride out temporary errors and rate limits.
- Token tracking, so you know what each run cost.
utf-8-sig, so Excel shows accents and emoji correctly.
2. The model returns the topic "Packaging," which isn't in your list. What does the script do?
Validation keeps unexpected answers from quietly contaminating your results.
Controlling costs
Before processing thousands of rows, estimate the cost with a small test. An example using the prices Anthropic published in November 2026 for Claude Sonnet 5.5: $2 per million input tokens and $10 per million output tokens (prices change, so always check the official pricing page):
| Item | Calculation | Result |
|---|---|---|
| Input tokens (1,000 reviews × 300) | 300,000 × $2 / 1,000,000 | $0.60 |
| Output tokens (1,000 reviews × 60) | 60,000 × $10 / 1,000,000 | $0.60 |
| Total | $1.20 |
Output is only 20% of the tokens but costs as much as the input, because each output token is five times more expensive. That's why limiting max_tokens and asking for short answers saves money.
By hand, a thousand reviews could take a full day. Before running a large batch, tick off this list:
Using the API doesn't remove the obligations from lesson 12: read the provider's data-use terms, anonymize when you can (remove names, Social Security and account numbers, phone numbers) and comply with the privacy laws that apply to your customers before sending their information.
Checking the quality of the output
A process that's wrong 10% of the time can be very useful or a disaster, depending on what you decide with it. Measure before you trust it:
- Classify 50 rows by hand (your "answer key") and compare them with the script's output.
- Study the errors: a missing category? Ambiguous cases? Would examples in the instructions help (lesson 5)?
- Adjust the instructions and measure again on the same sample.
- Once it's running, review every "REVIEW" row plus a random sample regularly.
3. You're going to process 20,000 invoices for the first time. What do you do first?
A small test tells you whether the prompt works and what the full run will cost, before you spend time and money.
4. The batch of 1,000 reviews costs $1.20 through the standard API. If you send it through the Batch API with a 50% discount, how much do you pay?
Anthropic's batch discount applies to both input and output: $1.20 × 50% = $0.60. In exchange, the results don't come back instantly.
Practice exercise: an order-data extractor
Modify classify.py so it processes a CSV of customer requests (column message) and extracts these columns: product_name, quantity (a number or empty), urgent (yes/no) and needs_human (yes/no). Test it on 10 messages you write yourself, including two that have nothing to do with orders.
See solution
INSTRUCTIONS = """You extract data from customer order messages.
Reply ONLY with valid JSON in this shape:
{"product_name": "text or null", "quantity": number or null,
"urgent": "yes|no", "needs_human": "yes|no"}
Rules:
- Use null if the data isn't in the message. Don't guess quantities.
- urgent = "yes" only if the customer mentions a close date or the word urgent.
- needs_human = "yes" if it's a complaint, a question that isn't an order,
or the message is ambiguous."""
def validate(data):
if data.get("urgent") not in ("yes", "no"):
data["urgent"] = "REVIEW"
if data.get("needs_human") not in ("yes", "no"):
data["needs_human"] = "REVIEW"
qty = data.get("quantity")
if qty is not None and not isinstance(qty, (int, float)):
data["quantity"] = "REVIEW"
return data
# In classify(): replace the "topic" check with
# data = validate(json.loads(text))
# and in main() read row["message"] instead of row["review"].
Check that the two non-order messages come back with an empty product_name and needs_human = "yes". validate() is strict on purpose: a capitalized "Yes" or a quantity like "two" gets flagged "REVIEW."
Summary
- The API lets you use models from your own code, paying per input and output token.
- Keep the key in an environment variable and set a spending limit.
messages.createtakes the model, the token limit, the instructions (system) and the messages.- The API has no memory: to hold a conversation, send the full history.
- For batch work: exact format, validation, handled errors, a small test first and measured quality.
Next lesson: How to Implement AI in a Business: Use Cases, ROI, Pilot and Policy. You'll move from your own projects to the organization, from choosing use cases to measuring the return.
Create your account in 30 seconds, mark your lessons and download your certificate at the end.