← Blog

Claude API Authentication Header Format Explained

2026-10-22 · 4 min read · SubToAPI Team

Claude's API does not use the Authorization: Bearer header that most REST APIs expect. Instead, Anthropic's native API uses a custom header called x-api-key, combined with a required anthropic-version header. If you're getting 401 or 400 errors despite having a valid key, the cause is almost always a missing or malformed header, not an invalid key.

Here is the exact format for a correct request to the native Claude API:

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-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello, Claude"}]
  }'

Three headers matter here, and missing any one of them produces a different failure mode.

The three required headers

x-api-key This replaces the Authorization header entirely. Do not send Authorization: Bearer sk-ant-... to api.anthropic.com — it will be ignored or rejected depending on the endpoint. The key goes in x-api-key as a raw string, no Bearer prefix, no quotes around the value in the header itself.

anthropic-version This is a required date-stamped version string (e.g. 2023-06-01) that tells the API which request/response schema to use. Omitting it returns a 400 error, not a 401, which confuses people who assume the problem is their key. Anthropic rolls out breaking changes behind new version strings, so pinning this value in your config is good practice — don't let it drift unintentionally across environments.

content-type: application/json Required for any POST with a JSON body. Without it, some HTTP clients (older versions of requests in Python, for instance) will silently send text/plain and the request will fail with a generic 400.

A minimal JavaScript example

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

const data = await response.json();
console.log(data);

If you're using Anthropic's official SDKs (@anthropic-ai/sdk for Node, anthropic for Python), the SDK sets all three headers for you automatically once you pass the API key to the client constructor. Most header-format bugs happen when people build raw HTTP requests by hand or port a cURL snippet from a different API's documentation.

Common mistakes that cause auth failures

Why this trips people up

Most developers' mental model of API auth is Authorization: Bearer <token>, because that's the convention used by OAuth2, Stripe, GitHub, OpenAI, and dozens of other APIs. Claude's native API deliberately deviates from that convention. If you're switching a codebase from OpenAI's API to Claude's, or building a provider-agnostic LLM client, this is the header change that catches people most often — not the request body format, not the model names, the headers.

If you want standard Bearer-token auth instead

If your use case is to expose Claude access as an internal or external API for your own application — giving teammates or services their own scoped keys, usage tracking, and standard Authorization: Bearer auth — building and maintaining that gateway yourself means handling key issuance, per-key usage metering, rate limiting, and streaming reconnection logic on top of the native header format above.

SubToAPI does this for you: it sits in front of your Claude access and issues standard sub_live_... application keys that your own apps or teammates use with a normal Authorization: Bearer $SUBTOAPI_KEY header, over plain HTTPS. You keep the x-api-key / anthropic-version complexity on the SubToAPI side, and your application code gets a familiar Bearer-token interface, streaming, tool use, and per-key usage metadata in one dashboard. See the quickstart or the messages endpoint docs for the exact request shape, and /pricing for plan details (Solo €9, Team €19/seat, Scale €49/seat, free trial at signup).

Quick checklist for debugging a 401/400

  1. Confirm you're sending x-api-key, not Authorization, to api.anthropic.com.
  2. Confirm anthropic-version is present and set to a valid date string.
  3. Print the raw header value in your client code and check for stray whitespace or quote characters.
  4. Confirm the key belongs to the workspace you think it does — test it with a trivial curl request in isolation before blaming your application code.
  5. Check content-type: application/json is set on POST requests with a body.

Questions

Does Claude's API support Authorization: Bearer at all? Not on Anthropic's native api.anthropic.com endpoints — those require x-api-key. Some gateways and proxies, including SubToAPI, accept standard Authorization: Bearer keys and translate them internally.

What happens if I omit anthropic-version? You get a 400 error indicating a missing required header, not a 401. It's easy to mistake this for an invalid key if you're not reading the error body closely.

Can I rotate my API key without changing the header format? Yes. The header name and structure (x-api-key: <value>) stay the same; only the key value changes. Update the value in your secrets manager or environment variable and redeploy — no code changes needed.

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 →