Your first API call, four vendors
Every vendor's API takes the same three things (a model name, your text and a cap on the reply) and hands back the same two (the text and a token count). Get a key from each of the four, send one request with curl, read the reply, and see what a failed call looks like. Commands and model names checked September 2026.
- 1Your terminalcurl, with the key read from an environment variable
- 2The requestModel name, your text, a cap on the reply, the key in a header
- 3The vendor's APIOpenAI, Google Gemini, xAI or Anthropic
- 4The replyJSON: the answer, a stop reason, and the tokens used
An error comes back the same way, as JSON with a status code.
Get a key
Each vendor issues keys from its own developer console, separate from the chat app you already use. A ChatGPT, Gemini, Grok or Claude subscription does not include API use; the API is billed on its own account.
| Vendor | Where the key is made | Environment variable in its quickstart | Quickstart |
|---|---|---|---|
| OpenAI | The API platform dashboard, API keys | OPENAI_API_KEY |
OpenAI quickstart |
| Google AI Studio, Get API key | GEMINI_API_KEY |
Gemini quickstart | |
| xAI | The xAI console, API keys (add credits first) | XAI_API_KEY |
xAI quickstart |
| Anthropic | The Claude Console, API keys | ANTHROPIC_API_KEY |
Claude get started |
If the key is for work, ask your IT or security office before you make one. Many organizations already hold an account with one of these vendors and would rather issue you a key under it.
Keep the key in the environment
The key goes into an environment variable for the current terminal, and every command below reads it from there. On macOS or Linux, this prompts for the key without echoing it and without writing it to your shell history:
read -rs ANTHROPIC_API_KEY && export ANTHROPIC_API_KEY
Swap the variable name for the vendor you are using. Close the terminal and the key is gone from memory, which is what you want while learning. The Windows version is on the PowerShell page.
The shape of a request
Four vendors, four slightly different spellings of the same request.
| OpenAI | Google Gemini | xAI | Anthropic | |
|---|---|---|---|---|
| Address | api.openai.com/v1/responses |
generativelanguage.googleapis.com/v1beta/interactions |
api.x.ai/v1/responses |
api.anthropic.com/v1/messages |
| Key header | Authorization: Bearer |
x-goog-api-key |
Authorization: Bearer |
x-api-key plus anthropic-version |
| Your text | input |
input |
input |
messages |
| Reply cap | max_output_tokens |
generation_config.max_output_tokens |
max_output_tokens |
max_tokens (required) |
input takes a plain string, or a list of messages with a role and content, the same list Anthropic calls messages. The model name is always the first field. Copy a current ID from the vendor's model list (OpenAI, Gemini, xAI, Anthropic); the IDs below are the ones the quickstarts used in September 2026 and will change.
One call per vendor
Each block is one command. The key comes from the environment; nothing secret is typed on the line.
OpenAI
curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{"model": "gpt-6-astra", "max_output_tokens": 300,
"input": "Rewrite as one plain sentence: the meeting is moved to Thursday."}'
Google Gemini
curl https://generativelanguage.googleapis.com/v1beta/interactions \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{"model": "gemini-3.8-flash", "generation_config": {"max_output_tokens": 300},
"input": "Rewrite as one plain sentence: the meeting is moved to Thursday."}'
xAI
curl https://api.x.ai/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $XAI_API_KEY" \
-d '{"model": "grok-4.7", "max_output_tokens": 300,
"input": "Rewrite as one plain sentence: the meeting is moved to Thursday."}'
Anthropic
curl https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{"model": "claude-opus-5-5", "max_tokens": 300,
"messages": [{"role": "user",
"content": "Rewrite as one plain sentence: the meeting is moved to Thursday."}]}'
Google announced the interactions address in 2026 as the one for new projects; the older generateContent address still works and appears in many examples online (Gemini interactions).
Reading the reply
The reply is JSON. Trimmed, the Anthropic one looks like this:
{"model": "claude-opus-5-5",
"role": "assistant",
"content": [{"type": "text", "text": "The meeting has moved to Thursday."}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 21, "output_tokens": 9}}
Three things to find in every reply, whoever sent it:
| OpenAI and xAI | Google Gemini | Anthropic | |
|---|---|---|---|
| The text | output, the item of type message, its content text |
steps, the step of type model_output, its content text |
content, the block of type text |
| Why it stopped | status (completed or incomplete) |
status |
stop_reason (end_turn or max_tokens) |
| Tokens used | usage.input_tokens, usage.output_tokens |
usage.total_input_tokens, usage.total_output_tokens, usage.total_thought_tokens |
usage.input_tokens, usage.output_tokens |
Find the text by its type, not its position. OpenAI's text guide says so directly: a reasoning model can put other items ahead of the message, so the first item is not always the answer (OpenAI text generation). To see the whole reply laid out, pipe it through a formatter: curl ... | python3 -m json.tool.
Tokens are the bill
The usage block is the meter. Input tokens are everything you sent; output tokens are everything it wrote, and on a thinking model that includes the thinking you never see. Output costs more per token than input on every vendor's price page. Write the two numbers down for your first ten calls and you will know what a thousand calls cost before you run them; API costs and limits turns that into a budget.
The cap matters for the same reason. Set it too high and a runaway reply bills you for pages you did not want. Set it too low on a thinking model and the model can spend the whole allowance thinking and hand back an empty answer with incomplete or max_tokens as the reason. If the text is missing, check the stop reason before anything else.
What an error looks like
A failed call still returns JSON, with an HTTP status code in front of it. Add -i to curl to see the status line. A bad key on the Anthropic API returns something like:
{"type": "error",
"error": {"type": "authentication_error", "message": "invalid x-api-key"}}
| Status | Usual meaning | What to do |
|---|---|---|
| 400 | The request is malformed: a missing field, bad JSON, a cap above the model's limit | Read the message; it names the field |
| 401 | The key is missing, mistyped or revoked | Check the variable is set in this terminal (echo ${#OPENAI_API_KEY} prints its length, not the key) |
| 403 | The key is valid but not allowed this model or region | Check the account's access in the console |
| 404 | The model ID or address is wrong | Copy the ID from the vendor's model list |
| 429 | Too many requests or tokens per minute, or the account's spend limit is reached | Wait the number of seconds in the retry-after header, then slow down |
| 500, 503, 529 | The vendor's side is busy or failing | Wait and try once more; do not loop |
Each vendor lists its own codes: OpenAI, Anthropic, Gemini. A 429 is the one you will meet most. It is a speed limit, not a fault, and the fix is a slower loop.
Keeping the key out of files
The quick way to leak a key is to make it part of the script, then share the script. Four habits prevent it:
- Read it from the environment in code.
os.environ["OPENAI_API_KEY"]in Python,$env:OPENAI_API_KEYin PowerShell. The script can then be shared, committed or pasted into a chat for help with no secret inside. - If you keep it in a
.envfile, keep that file out of everything. Add.envto.gitignorebefore the first commit, and never attach it, sync it to a shared drive or open it during a screen share. - One key per job. Name each key in the console after the script that uses it. When one leaks, you delete that key and nothing else breaks.
- Delete on doubt. If a key has been anywhere it should not be, delete it in the console and make a new one. It takes a minute.
Google's own key guidance says the same: never check a key into source control, and never build one into a web or mobile app (Gemini API keys).
What to do with this
Make a key with one vendor, send the call above, and find the three things in the reply. Then change the cap to 5 and see the stop reason change. On Windows, the PowerShell version is next; otherwise go to recipes that work on any of the four.
Vendor facts checked ; re-verify before relying on them.