← Blog

Claude API Authentication Headers: Example Code

2026-09-28 · 4 min read · SubToAPI Team

Every request to Anthropic's Claude API needs three headers to authenticate and be understood correctly: x-api-key, anthropic-version, and content-type. Miss one of these and you'll get a 401 or 400 error instead of a completion. This article shows the exact header format, working code in curl and JavaScript, and the mistakes that most commonly break authentication.

The short answer: Claude does not use the Authorization: Bearer pattern that OpenAI and most REST APIs use. Instead, your API key goes into a custom header called x-api-key. If you copy-paste boilerplate from another provider's docs, this is almost always the first thing that breaks.

The Required Headers

Here's the minimal header set for any request to https://api.anthropic.com/v1/messages:

x-api-key: sk-ant-api03-xxxxxxxxxxxxxxxxxxxxx
anthropic-version: 2023-06-01
content-type: application/json

curl Example

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Explain what a vector database is in two sentences."}
    ]
  }'

Store your key in an environment variable rather than hardcoding it. If you're testing locally, export ANTHROPIC_API_KEY=sk-ant-... in your shell before running curl.

JavaScript / Node.js Example

Using fetch directly, without any SDK:

const response = await fetch("https://api.anthropic.com/v1/messages", {
  method: "POST",
  headers: {
    "x-api-key": process.env.ANTHROPIC_API_KEY,
    "anthropic-version": "2023-06-01",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-20250514",
    max_tokens: 1024,
    messages: [
      { role: "user", content: "Summarize the plot of Hamlet in one paragraph." },
    ],
  }),
});

const data = await response.json();
console.log(data.content[0].text);

This is the whole authentication flow — no OAuth handshake, no token refresh cycle, no signing algorithm. It's a static key in a header, which is simple but also means you're responsible for keeping it out of client-side code, logs, and version control.

Common Authentication Errors

401 Unauthorized — "invalid x-api-key" Usually means the key is malformed, expired, or you used Authorization: Bearer instead of x-api-key. Double-check you copied the full key string, including the sk-ant- prefix.

400 Bad Request — missing anthropic-version This header is mandatory. If you leave it out, some client libraries will silently inject a default, but raw fetch or curl calls will fail immediately.

403 Forbidden Your key is valid but doesn't have access to the requested model or feature (for example, a model still in limited access). Check the Anthropic Console for which models your account can call.

Key exposed in a public repo If you accidentally commit a key, rotate it immediately in the console — old keys don't expire automatically.

Server-Side vs Client-Side Requests

Because x-api-key is a long-lived secret with no scoping by default, you should never call the Claude API directly from a browser or mobile app. Anyone opening dev tools sees your key and can drain your usage limits. The standard pattern is:

  1. Your frontend calls your own backend.
  2. Your backend attaches x-api-key and forwards the request to Anthropic.
  3. Your backend streams or returns the response to the frontend.

This adds a maintenance burden: you now own a proxy layer, plus key rotation, per-user rate limiting, and usage tracking if you want to bill different app users differently.

Simplifying Auth for Multi-User Apps

If you're building a product on top of Claude rather than a personal script, raw x-api-key headers get harder to manage once you have multiple environments, team members, or app users who each need scoped access. SubToAPI sits on top of your existing Claude access and issues its own application-level keys (sub_live_...) that you can create per app, per environment, or per customer, without touching your underlying Anthropic key.

Authenticating against SubToAPI still uses a familiar header pattern:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Here it's standard Authorization: Bearer, so it drops into existing HTTP client setups, SDKs, and API testing tools without custom header handling. You also get streaming, tool use, usage metadata per key, and team seats in one dashboard — useful if multiple developers or services need independent, revocable credentials instead of one shared secret. Start with a free trial at /signup, check /pricing for plan details, or read the /docs/quickstart for a full setup walkthrough. Header and request formats for messages and streaming are documented at /docs/messages and /docs/streaming.

Quick Checklist

Before you debug further, verify:

Questions

Does Claude API authentication use Bearer tokens? No. Anthropic's native API uses a custom x-api-key header with your raw key, not Authorization: Bearer. Some third-party layers built on top of Claude, like SubToAPI, do use standard Bearer tokens.

What happens if I omit the anthropic-version header? The request will typically fail with a 400 error, since the API needs to know which version of the request/response schema to apply. Always set it explicitly rather than relying on a default.

Can I call the Claude API directly from frontend JavaScript? Technically yes, but you shouldn't — your API key would be visible to anyone inspecting network requests. Route calls through a backend or a managed layer that issues scoped, revocable keys instead.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →