Foundations · Setup

Setting Up Your Environment

Before you write a line of agent code, you need three things: an API key, a safe place to keep it, and a working SDK. This page gets all three in place and ends with the same "hello, Claude" call made two different ways.

☺ Explain it like I'm 10

An API key is like a house key: platform.claude.com hands you a fresh-cut copy, and it shows you the full key exactly once. You don't tape a house key to your front door — you keep it in a locked drawer. For code, that "locked drawer" is an environment variable, loaded from a .env file that never gets mailed off with the rest of your project.

🐧Your host for this topic: Pico the Penguin (treats environment setup like laying out tools before the real build starts).

Create your Console account and generate an API key

☺ Like you're 10: Think of this like getting a library card before you're allowed to borrow anything — you need the key before Claude will say a word back to you.

Every Claude API call is authenticated with an API key issued from the Console. Go to platform.claude.com — this is now the shared home for both the Console and the docs, and the older console.anthropic.com and docs.claude.com addresses redirect here — and sign in or create an account.

Once you're in, open Settings → API keys and click Create key. You'll be asked to:

⚠ Careful

The Console shows the full key — it starts with sk-ant- — exactly once, at creation time. Copy it somewhere safe immediately. If you lose it, there's no way to retrieve it again; you'll have to create a new key.

Store the key as an environment variable — never hardcode it

☺ Like you're 10: It's the difference between hiding your house key under a rock only you know about, versus writing your address and key shape on a public bulletin board.

Both official SDKs, and the raw HTTP API, look for your key in the ANTHROPIC_API_KEY environment variable, so that's the one you should set. Anthropic's own authentication guidance is blunt about this: store keys in a secrets manager, set them as an environment variable, never commit them to source control, rotate them periodically, and revoke any key you suspect has leaked.

◆ Pattern

Read the key from os.environ / process.env, populated from a local .env file that is excluded from version control.

⚠ Anti-pattern

Pasting sk-ant-api03-... directly into a Python string, a notebook cell, or a committed config file.

The standard local-development pattern is a .env file at your project root, loaded by a small dotenv library so the variable ends up in the process environment before your code runs.

# .env  (project root, never committed)
ANTHROPIC_API_KEY=sk-ant-api03-your-key-here
Python
# pip install python-dotenv
from dotenv import load_dotenv
import os

load_dotenv()  # reads .env into the process environment

print("Key loaded:", os.environ["ANTHROPIC_API_KEY"][:12] + "...")
JavaScript
// npm install dotenv
import "dotenv/config"; // reads .env into process.env as a side effect

console.log("Key loaded:", process.env.ANTHROPIC_API_KEY?.slice(0, 12) + "...");

You can also export the variable directly in your shell for a one-off session, which is handy when testing from the terminal:

export ANTHROPIC_API_KEY="sk-ant-api03-..."
⚠ Careful

Add .env to your .gitignore before you create the file, not after. A key that's already in your git history is compromised even if you delete the file in a later commit — treat it as leaked and revoke it from the Console.

# .gitignore
.env
.env.*
__pycache__/
node_modules/
🎬 At the Claude Crew
🦊

Foxy: I just pasted my API key straight into my Python script so I wouldn't lose it. Problem solved, right?

🦉

Professor Owl: Not quite — if that file ever reaches GitHub, the key is public forever, even if you delete it in a later commit.

🦊

Foxy: Even after I delete it?

🦉

Professor Owl: Especially after — it's still sitting in the commit history, waiting.

🐧

Pico: Keep it in .env, gitignore that file before you ever save it, and load it with dotenv. Your code then never touches the literal key string.

Install the SDKs

Anthropic publishes official SDKs for Python and TypeScript/JavaScript. Install whichever matches the language you're working in — you don't need both unless you're following along with every example in this course.

pip install anthropic
npm install @anthropic-ai/sdk

Both SDKs read ANTHROPIC_API_KEY from the environment automatically when you construct a bare client — no key needs to appear in your code at all.

Your first call: "hello, Claude"

☺ Like you're 10: You're mailing a letter (your question) to Claude's address, and the reply comes back in a labeled envelope so your code knows exactly what kind of thing it's holding before it reads it.

Underneath both SDKs is the same HTTP request: a POST to /v1/messages with a model, a max_tokens limit, and a messages array whose first entry has role: "user". The response comes back as a content array of typed blocks, so you check block.type == "text" before reading block.text — a response can in principle contain other block types alongside or instead of text.

Your codebuilds the request POST /v1/messagesmodel + max_tokens + messages api.anthropic.comClaude generates a reply content: [ ]typed blocks, e.g. text

Here's the identical request in Python and JavaScript. Both ask Claude the same question and print the resulting text.

Python
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from env

message = client.messages.create(
    model="claude-opus-5",
    max_tokens=1000,
    messages=[
        {
            "role": "user",
            "content": "What should I search for to find the latest developments in renewable energy?",
        }
    ],
)

for block in message.content:
    if block.type == "text":
        print(block.text)
JavaScript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic(); // reads ANTHROPIC_API_KEY from env

const message = await client.messages.create({
  model: "claude-opus-5",
  max_tokens: 1000,
  messages: [
    {
      role: "user",
      content: "What should I search for to find the latest developments in renewable energy?"
    }
  ]
});

for (const block of message.content) {
  if (block.type === "text") {
    console.log(block.text);
  }
}

Both SDKs do a few things by hand for you under the hood: they set an x-api-key header from your environment variable and add an anthropic-version header that pins the API's dated schema version. If you ever need to debug an SDK issue, knowing those two headers exist is a fast way to tell whether a problem is in your code or in the request itself.

⌁ Note

Model names change as Anthropic ships new generations, so treat claude-opus-5 above as an example, not a permanent constant. Check the live Models Overview page in the Console before you hard-code a model ID into anything long-lived, and consider centralizing the string in one config value or environment variable so upgrading is a one-line change.

Doing this in VS Code

☺ Like you're 10: VS Code is your workbench — this section is just where the "run" button lives for each kind of file.

This course uses VS Code as its reference editor, so it's worth knowing the couple of ways you'll typically run this code there.

Running a .py file from the integrated terminal

Save the Python snippet above as hello_claude.py, open VS Code's integrated terminal (Ctrl+` / Cmd+`), make sure the Python extension has selected the interpreter for the virtual environment where you ran pip install anthropic python-dotenv, and run:

python hello_claude.py

Using an interactive Python cell

If you have the Python extension installed, you can add a # %% comment above a block of code to turn it into a runnable Jupyter-style cell directly inside a .py file — VS Code shows a "Run Cell" link above it and opens results in the Interactive Window. This is a convenient way to iterate on a prompt and inspect message.content without re-running the whole script each time.

Running a .ts file with ts-node

For the TypeScript version, save the snippet as hello-claude.ts, install a TypeScript runner in the integrated terminal, and execute it directly:

npm install -D typescript ts-node @types/node
npx ts-node hello-claude.ts

If you'd rather skip a TypeScript-specific runner, compile with tsc and run the emitted JavaScript with plain node, or write the example directly as a .mjs file using node hello-claude.mjs.

⌁ Note

If you install the Claude Code extension for VS Code later in this course, it's a separate, complementary tool: an agentic coding assistant that lives in its own panel, not a replacement for running your own Python/JavaScript scripts in the terminal. You'll set it up when the course gets to agentic workflows.

Troubleshooting

SymptomLikely causeFix
401 / authentication errorKey missing, wrong, revoked, or expiredConfirm ANTHROPIC_API_KEY is set (echo $ANTHROPIC_API_KEY) and that it matches an active key in Settings → API keys; generate a new one if needed
KeyError / undefined reading the API key.env not loaded before the client is constructedCall load_dotenv() (Python) or import dotenv/config (Node) before creating the Anthropic client, and confirm the file is literally named .env in your working directory
Works in one terminal, fails in anotherEnvironment variable was exported in a shell session that isn't the one VS Code is usingPrefer the .env + dotenv pattern over ad-hoc export, since it travels with the project instead of the shell session
TypeError on SDK methods, or missing parameters like max_tokensSDK version mismatch with the code sampleCheck installed version (pip show anthropic / npm list @anthropic-ai/sdk) against the latest on PyPI/npm and upgrade if it's old
429 rate limit errorToo many requests too fast for your usage tierExpected while testing; the SDKs retry transient failures automatically with backoff — space out repeated manual runs
A raw HTTP request hangs or returns HTML instead of JSONMissing or malformed headersDouble-check all required headers are present: content-type: application/json, x-api-key, and anthropic-version
✎ Try it yourself

Create a fresh project folder with a .env file (and a .gitignore that excludes it) holding your real API key. Write hello_claude.py using the Python snippet above, but change the user message to ask Claude to explain, in one sentence, what an API key is. Run it from the VS Code integrated terminal, then write and run the equivalent JavaScript version and confirm both print a similarly-shaped answer.

🐧 Pico's checkpoint

You should now be able to explain where an API key comes from, why it belongs in an environment variable instead of your code, and what a minimal Messages API call needs — a model, max_tokens, and a messages array — plus how to safely read the typed content blocks it returns. Next up: Messages API Basics, where you'll build on this first call.

Check your answers
  1. Where do you get an API key, and how many times can you see it in full? From platform.claude.com under Settings → API keys; the full key (starting with sk-ant-) is shown only once, at creation, so you must copy it immediately or generate a new one if it's lost.
  2. Why store the key in an environment variable instead of pasting it into code? A hardcoded key ends up in source control and is compromised the moment it's committed, even if you delete it later; setting ANTHROPIC_API_KEY and loading it from a gitignored .env file keeps the literal string out of your files and git history.
  3. What three things does every Messages API call need, and what should you check before reading the reply? A model, a max_tokens limit, and a messages array starting with role: "user"; the response arrives as a content array of typed blocks, so check block.type == "text" before reading block.text.