AI Tools Field Guide

Open edition · no CAC needed

Advanced — Build with it

  1. 1Your terminalcurl, with the key read from an environment variable
  2. 2The requestModel name, your text, a cap on the reply, the key in a header
  3. 3The vendor's APIOpenAI, Google Gemini, xAI or Anthropic
  4. 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 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:

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.