How to Use a Claude API Key: Auth, Calls, and Limits
Once you have a Claude API key, using it comes down to one thing: attaching it correctly to your HTTP requests so the API can authenticate you and bill usage to your account. In practice that means setting the right header on every call to the Messages endpoint, structuring your request body correctly, and handling the response format Claude returns — whether that's a single JSON payload or a stream of events.
This guide walks through the mechanics: where the key goes, what a minimal working request looks like, how to handle streaming and tool use, and the security habits that keep a leaked key from becoming an expensive problem. It assumes you already have a key in hand and just want to start making calls that work.
Where the API key actually goes
Claude API keys are passed as an HTTP header on every request, not as a URL parameter and not in the request body. A typical header looks like:
x-api-key: sk-ant-api03-...
anthropic-version: 2023-06-01
content-type: application/json
The anthropic-version header pins your request to a specific API version, which matters because response formats can change between versions. If you omit it, you're relying on a default that may shift over time — always set it explicitly in production code.
Making your first request
Here's a minimal call to the Messages endpoint using curl:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $CLAUDE_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"messages": [
{"role": "user", "content": "Explain what a race condition is in one paragraph."}
]
}'
And the equivalent in JavaScript using fetch:
const response = await fetch("https://api.anthropic.com/v1/messages", {
method: "POST",
headers: {
"x-api-key": process.env.CLAUDE_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json",
},
body: JSON.stringify({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1024,
messages: [
{ role: "user", content: "Explain what a race condition is in one paragraph." },
],
}),
});
const data = await response.json();
console.log(data.content[0].text);
Three fields are required on every call: model, max_tokens, and messages. The messages array holds the conversation history, alternating user and assistant roles. If you need a system prompt, it goes in a separate top-level system field, not as a message.
Handling streaming responses
For anything user-facing, you generally don't want to wait for the full response before rendering it. Setting "stream": true in the request switches the response to server-sent events, where each chunk arrives as a data: line you parse incrementally. This is the same pattern used across most LLM APIs, so if you've built against OpenAI's streaming before, the shape will feel familiar — the event types and payload structure differ, but the transport mechanism (SSE over a long-lived HTTP connection) is the same.
Streaming changes how you write your client code: instead of a single await response.json(), you read the response body as a stream and reconstruct text incrementally as content_block_delta events arrive. It's more code up front but produces a noticeably better experience for chat interfaces.
Using tools with your key
Tool use (function calling) works by describing available tools in the request — name, description, and a JSON schema for inputs — and letting the model decide when to call one. The response comes back with a tool_use content block instead of plain text when Claude wants to invoke a tool. Your code executes the tool, then sends the result back in a follow-up message with a tool_result block so Claude can continue the conversation with that data in hand. The API key itself doesn't change for tool calls — the same header and endpoint are used — but the request and response shapes get more complex, and it's worth reading through a few examples before wiring this into a production agent loop.
Rate limits, retries, and key rotation
API keys are tied to usage tiers that cap requests per minute and tokens per minute. When you hit a limit, the API returns a 429 status — your code should back off and retry rather than fail the request outright. A simple exponential backoff with jitter handles the vast majority of rate-limit errors gracefully.
Rotating keys periodically, especially after an employee leaves a team or a key is accidentally logged, is good hygiene. Never hardcode a key in source code or commit it to version control — use environment variables and a secrets manager for anything beyond local testing.
Where SubToAPI fits into this
Everything above describes calling Claude's API directly with a single key against a single account. That's fine for a solo project, but it gets harder once you have multiple applications, a team that needs separate credentials, or a need to see per-app usage without digging through raw logs.
SubToAPI sits on top of your existing Claude access and turns it into a clean HTTPS API with per-application keys (sub_live_...), so you're not sharing one master key across every service you build. It supports the same core patterns described here — Messages, streaming, tool use — documented at /docs/messages, /docs/streaming, and /docs/tools. If you're setting this up for a team rather than a single script, /docs/quickstart is the fastest way to get the first authenticated call working, and /pricing covers the Solo, Team, and Scale plans if you outgrow a single key. You can start with a free trial at /signup.
Questions
Do I put my Claude API key in the URL or a header? Always in a header — specifically x-api-key — alongside anthropic-version and content-type. Putting a key in a URL risks it being logged in server access logs or browser history.
Can I use the same Claude API key from a frontend app? No. API keys should never be exposed in client-side code, since anyone inspecting network requests could copy and reuse them. Call the API from a backend service and have your frontend talk to that instead.
What's the difference between using the key directly and using a service like SubToAPI? Using the key directly means one credential authenticates every request across every app you build. SubToAPI issues separate application-level keys on top of your Claude access, giving you per-app usage visibility and easier key management without changing how the underlying Messages, streaming, or tool-use calls work — see /docs/quickstart for the setup.