Skip to content
Zarif Automates

AI APIs for Beginners: Make a Request and Handle the Response

ZarifZarif
Published Updated

An AI API lets your application ask a model to do a task. The useful part is getting the answer back into your own workflow: a support ticket becomes a proposed label, a document becomes extracted fields, or a question becomes a draft response.

Start with one small request. In this lesson you'll build a short Python program that asks Claude to label a fake support ticket, and only accepts one of three labels back.

You'll also run eight practice cases on your own machine. They show you what happens when your key is rejected, when you've sent too many requests too fast, and when the answer comes back in a form you can't use.

Download the complete Python example. Run it normally and it only does the local practice cases. Add --live and it sends one real request to Anthropic. That needs your own API account and may cost money.

What you need

You need Python 3.10 or newer and a terminal. The example only uses what comes with Python, so there's nothing to install. Save the download as api_lesson.py in a new folder.

For a real request to the model, you also need an Anthropic API key, access to a model, and money or credit on your API account.

An API key is a password for your account, so treat it like one. Keep it on your machine. Don't put it in browser JavaScript, a code file, a screenshot, or a Git commit. The local practice cases need no key and never call the model.

1. Read the request you are about to send

To talk to the Messages API, your program sends an HTTP POST request to https://api.anthropic.com/v1/messages. Think of it as mailing a package. The headers are the label on the outside. Three of them matter here:

HeaderPurpose
x-api-keyAuthenticates your API account
anthropic-version: 2023-06-01Selects the documented API version
content-type: application/jsonIdentifies the request body's format

What goes inside the package is the body, written as JSON. That's where the model name and the output limit go. The download builds this body, with a system instruction telling the model to answer with one label only:

payload = {
    "model": model,
    "max_tokens": 1024,
    "system": 'Return only JSON with one key, "label": billing, technical, or other.',
    "messages": [{
        "role": "user",
        "content": "I was charged twice for invoice INV-DEMO-42."
    }],
}

The full instruction in the download also tells the model that the ticket text is just data to read, and that it shouldn't take any actions. That helps. But your program still has to check the answer.

Two things can go wrong. A customer can type sneaky instructions into a ticket. And a model can return the wrong label in perfectly valid JSON.

Models read and write in tokens, which are chunks of text a few characters long. max_tokens caps how many tokens the model can write back. It doesn't cap the total cost of the request, because the text you send in counts too.

This example tries once and doesn't retry on its own. Check your model's and account's limits before you try the live request.

2. Run the client against a local HTTP server

python3 api_lesson.py

If your system calls Python 3 python, use that instead.

The script starts a pretend API server on your own machine, at 127.0.0.1. It sends real HTTP requests to it, then shuts it down when the checks are done.

The pretend server checks that each request has the right version header, the test key, the message body and the output limit. Its replies are made-up examples shaped like Anthropic's real ones.

The result starts with:

{
  "mode": "local HTTP fixtures; no model call",
  "passed": 8,
  "results": [
    {"case": "ok", "outcome": "billing"}
  ]
}

Your output will show all eight rows. These checks were run on September 17, 2026. They prove your program handles the practice cases. They don't measure how accurately Claude labels tickets, and they don't prove your real API key works.

3. Understand the response before using it

A successful reply has three parts you care about: the content (the model's answer), a stop reason (why it stopped writing), and usage (how many tokens it used). Here's a shortened version of the practice reply:

{
  "type": "message",
  "stop_reason": "end_turn",
  "content": [{"type": "text", "text": "{\"label\":\"billing\"}"}],
  "usage": {"input_tokens": 0, "output_tokens": 0}
}

The token counts are zero because this is a practice reply. A real one reports actual usage.

Your program pulls out the text, reads it as JSON, and checks it against one strict rule: exactly one key named label, set to billing, technical, or other.

Anything else gets rejected. That includes extra fields, broken JSON, labels it doesn't know, and replies that didn't stop with end_turn, which is the stop reason for "finished normally".

Even an accepted label is only a suggestion. The script doesn't update a support system or email a customer. If you later want it to take an action like that, the action needs its own permission and review rules.

4. Inspect the failures

When something goes wrong, the API sends back a status code, a number that says what kind of problem it was. Anthropic's error reference lists them, and each reply includes a request ID you can give support when you need help.

Your program saves that ID, and any retry-after header telling it how long to wait. It never prints your API key.

Local caseObserved resultWhat to investigate with a real provider
Valid responsebilling acceptedWhether the label is correct for the ticket
HTTP 401Rejected; one attemptKey validity and account access
HTTP 429Rejected; retry delay retainedRate limit or applicable account limit
HTTP 500Rejected; one attemptProvider status and whether another attempt is justified
Unsupported labelRejectedPrompt, model behavior and allowed-label contract
Malformed JSONRejectedResponse format; do not strip arbitrary text until it parses
max_tokens stopRejectedOutput budget and task size
Refusal stopRejectedWhether the task is appropriate; do not treat refusal text as a label

A connection timeout is a different kind of failure. If the connection drops, your program can't know whether the request worked. The download has code to catch connection errors, but none of the eight practice cases tests a timeout.

A real app can retry some failures a limited number of times. Decide how many and how long to wait on purpose, because every retry is another request, and you pay for it.

5. Optionally send one real request

Only do this if you mean to use your own API account.

The script looks for your key in an ANTHROPIC_API_KEY environment variable. If it isn't there, it asks you to type it, and hides what you type. It doesn't save the key anywhere.

Set ANTHROPIC_MODEL to a model your account can use. The official API overview covers the Models endpoint, which tells you which models are available to you.

The example below uses claude-sonnet-5. Check the current model ID in the official docs and in your account before you run it. Which models you can use, and what they cost, depends on your account.

export ANTHROPIC_MODEL="claude-sonnet-5"
# The script prompts privately for your key if needed.
python3 api_lesson.py --live

The live request uses the same checking code as the practice cases. It's written to print the checked label, the request ID and the token usage. The label might not match the practice case.

To be clear about what was tested: only the local practice cases were run for this lesson. No paid call to Anthropic was made.

If the model wraps its JSON in a sentence like "Here's the label:", the strict check will reject it. That's fine. Let the failure show instead of hiding it.

For a bigger project, switch to the provider's built-in way of forcing structured output, and test it with the model you pick. An instruction in the prompt alone doesn't guarantee valid output.

Your deliverable

In the same folder as api_lesson.py, save the eight-case output, plus one new practice case you write yourself.

A good one to try: valid JSON with an extra send_email field. Your program should reject it and do nothing.

Next, go the other direction with webhook delivery, where another service sends a request to your app instead.

Zarif Choudhury

Zarif Choudhury

Zarif builds AI agents and automation workflows. He writes about what keeps working once real people use it: who is worth reading, the new jobs AI is creating, and agent workflows you can check step by step.