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.
- Sign in at
console.anthropic.comas an organization owner (admin keys cannot be created by member-tier users). - Open Settings → Admin Keys.
- Click Create Admin Key, give it a descriptive name (e.g.
cost-tracker-prod), and copy the value once. You cannot view it again. - Store it as
ANTHROPIC_ADMIN_KEYin 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"
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"
}
]
}
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
}
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"
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.
Top comments (0)