DEV Community

Sangmin Lee
Sangmin Lee

Posted on • Originally published at claudeguide.io

Anthropic Admin API: Usage, Costs & Workspaces (2026)

Originally published at claudeguide.io/anthropic-admin-api-tutorial

The Anthropic Admin API gives you read-only programmatic access to organization-level data: token usage, workspaces, members, and audit logs. It does not create messages — that is the regular Messages API. Admin keys carry the prefix sk-ant-admin-... (distinct from the message-sending sk-ant-api03-... keys) and authenticate to a separate surface area used by cost-tracking dashboards, finance integrations, and provisioning scripts. The three endpoints you will use 90% of the time are GET /v1/organizations, GET /v1/organizations/{id}/usage_report/messages, and GET /v1/organizations/{id}/workspaces. Rate limits on the Admin API are gentler than the Messages API because the calls are infrequent — a nightly cron is the typical pattern.

Admin API vs regular API

These are two different products with two different keys. Mixing them up is the most common first-day mistake.

Capability Messages API (sk-ant-api03-...) Admin API (sk-ant-admin-...)
Send messages to Claude Yes No
Stream completions Yes No
Use tools / files / batch Yes No
List organizations No Yes
Pull usage_report (token + cost data) No Yes
List/create workspaces No Yes
List/invite organization members No Yes
Read audit logs No Yes
Counts toward your message rate limits Yes No
Required anthropic-version header Yes Yes

If your code calls client.messages.create(...), you need a regular key. If your code is building a Grafana panel of "tokens spent yesterday by workspace," you need an admin key. Most production setups have both, stored as separate environment variables (ANTHROPIC_API_KEY and ANTHROPIC_ADMIN_KEY).

Generate an Admin API key

Admin keys are not visible from the regular API Keys page — they live one level up.

  1. Sign in at console.anthropic.com as an organization owner (admin keys cannot be created by member-tier users).
  2. Open Settings → Admin Keys.
  3. Click Create Admin Key, give it a descriptive name (e.g. cost-tracker-prod), and copy the value once. You cannot view it again.
  4. Store it as ANTHROPIC_ADMIN_KEY in your secret manager.

Admin keys are scoped to the organization that created them. They cannot be limited to a single workspace from the console — you scope by workspace at query time using the workspace_ids[] parameter on the usage endpoint.

Authentication

Every Admin API request needs two headers:

curl https://api.anthropic.com/v1/organizations \
  -H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
  -H "anthropic-version: 2023-06-01"
Enter fullscreen mode Exit fullscreen mode

The anthropic-version value is the same one used by the Messages API — 2023-06-01 is the current GA value as of May 2026. If you omit it, requests return 400 invalid_request_error.

GET /v1/organizations

Returns the organizations the key can see. For most accounts this is a single org, but enterprise setups with multiple billing entities will see more than one.

{
  "data": [
    {
      "id": "org_01ABCxyz...",
      "name": "Acme Corp",
      "created_at": "2024-08-12T18:42:11Z"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Cache the id — every other admin call needs it in the path.

GET /v1/organizations/{id}/usage_report/messages

This is the heavy hitter. It returns token consumption bucketed by time, model, and (optionally) workspace.

Query parameters:

Param Required Notes
starting_at yes RFC 3339 timestamp, inclusive. Max lookback ~13 months.
ending_at no Defaults to "now". Exclusive.
bucket_width no 1d (default) or 1h. 1m is not supported.
workspace_ids[] no Filter to one or more workspaces. Repeat the param.
models[] no Filter to specific models, e.g. claude-opus-4-7.

Response shape:

{
  "data": [
    {
      "starting_at": "2026-05-08T00:00:00Z",
      "ending_at": "2026-05-09T00:00:00Z",
      "results": [
        {
          "model": "claude-sonnet-4-6",
          "workspace_id": "wrkspc_01XYZ...",
          "input_tokens": 1842110,
          "output_tokens": 312044,
          "cache_creation_input_tokens": 88210,
          "cache_read_input_tokens": 1488221,
          "service_tier": "standard"
        }
      ]
    }
  ],
  "has_more": false
}
Enter fullscreen mode Exit fullscreen mode

Pagination: as of May 2026 the usage endpoint returns the entire window in a single response — has_more is reserved for future use but currently always false. That said, write your loop assuming pagination will land; you do not want to rewrite the integration when it does.

The four token fields matter independently because they price differently:

  • input_tokens — base input rate.
  • output_tokens — base output rate (about 5× input).
  • cache_creation_input_tokens — 1.25× input rate (one-time write cost).
  • cache_read_input_tokens — 0.1× input rate (the savings you came for).

Sum them with the right multipliers or your "total cost" number will be off by 30%+ on cache-heavy workloads.

GET /v1/organizations/{id}/workspaces

curl "https://api.anthropic.com/v1/organizations/$ORG_ID/workspaces" \
  -H "x-api-key: $ANTHROPIC_ADMIN_KEY" \
  -H "anthropic-version: 2023-06-01"
Enter fullscreen mode Exit fullscreen mode

Returns workspace IDs and display names. Use this to build a workspace_id → label lookup before you render any usage chart, otherwise your dashboard shows opaque wrkspc_01... strings.

Worked example: Python script for 30-day CSV

The script below pulls 30 days of usage, joins it with model pricing, and writes a CSV. Drop it on a cron and you have a finance feed.


python
#!/usr/bin/env python3
"""Pull 30-day Anthropic usage and emit cost CSV."""
import csv
import os
from datetime import datetime, timedelta, timezone

import requests

ADMIN_KEY = os.environ["ANTHROPIC_ADMIN_KEY"]
BASE = "https://api.anthropic.com/v1"
HEADERS = {"x-api-key": ADMIN_KEY, "anthropic-version": "2023-06-01"}

# Pricing per million tokens — refresh from claude-api-pricing-2026 quarterly.
PRICING = {
    "claude-opus-4-7":   {"in": 5.00, "out": 25.00, "cw": 6.25, "cr": 0.50},
    "claude-sonnet-4-6": {"in":  3.00, "out": 15.00, "cw":  3.75, "cr": 0.30},
    "claude-haiku-4-5":  {"in":  1.00, "out":  5.00, "cw":  1.25, "cr": 0.10},
}

def org_id() -

## Frequently Asked Questions

### Can the Admin API send messages?

No. The Admin API surface is read/management only — organizations, workspaces, members, invites, API keys, audit logs, and usage_report. To call `messages.create` you need a regular `sk-ant-api03-...` key. The two key types are not interchangeable: an admin key sent to `/v1/messages` returns `401 authentication_error` and a regular key sent to `/v1/organizations` returns the same.

### How recent is the usage data?

Expect a 1–2 hour lag at the daily bucket and slightly more for hourly. The `usage_report` is designed for finance and reporting, not for real-time rate limiting. If you need to cut off requests the moment a budget is hit, count tokens client-side from the Messages API response (`usage.input_tokens` etc.) and store running totals in Redis. Then reconcile against the Admin API daily.

### Can I rotate Admin keys without downtime?

Yes. Create a second admin key in the console, deploy it to your secret store under a new name, restart consumers, then revoke the old key. Admin keys do not have a built-in "next" slot like some providers offer, so you maintain rotation by always running with two valid keys overlapping for a few minutes.

### How do I scope by workspace?

Pass `workspace_ids[]` on the `usage_report/messages` call — repeat the param to list multiple. Example: `?workspace_ids[]=wrkspc_A&workspace_ids[]=wrkspc_B`. The response only includes results from those workspaces. There is no per-API-key filter, so the standard pattern is "one workspace per service" if you need fine-grained attribution.

### Are there official SDKs?

The standard `anthropic` Python and `@anthropic-ai/sdk` Node packages cover the Messages API but Admin API support has lagged — as of May 2026 most teams hit Admin endpoints with plain `requests` / `fetch` as shown above. Community wrappers exist on GitHub but the surface is small enough (≈12 endpoints) that hand-rolled typed fetchers are usually less hassle than another dependency.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)