claude-compliance-sdk
This is a community Python SDK for the Anthropic Compliance API — the API that lets you access Claude activity logs, chat data, and file content programmatically.
The Compliance API requires an Enterprise plan, and primary owners can enable it using the guide here.
Unofficial. This is a community-maintained project. It is not produced, endorsed, or supported by Anthropic.
📚 Read the documentation — full API reference, generated from the source.
Features
- Complete coverage of all Compliance API endpoints, including the Activity Feed, Chats, Messages, Files, Projects, Groups, Users, Roles, Permissions, Organisations, and session transcripts from Cowork and Claude Code.
- Full sync + async parity. Every resource method is available on both
ComplianceClientandAsyncComplianceClientunder the same name. - Typed responses as plain dataclasses. Unknown response fields are preserved in an
extra: dictso a future API revision adding a field cannot break the SDK. - Built-in retry with exponential backoff that treats
Retry-Afteras a floor, plus rate limiting driven by the server's ownanthropic-ratelimit-*headers — the client waits for the stated reset instead of spending a request to discover a 429. - Streamed downloads with a configurable memory ceiling — switch from eager bytes to
download_to_file()ordownload_stream()for anything larger. - Typed exception hierarchy. Every API error maps to a catchable class —
InvalidAPIKeyError,InsufficientScopeError,NotFoundError,ConflictError,RateLimitError, and the rest. - Tracks the hosted Anthropic Compliance API docs, snapshotted under
spec-snapshots/so upstream changes are visible as a diff.
Requirements
Python 3.11+.
Install
Install from PyPI with pip:
pip install claude-compliance-sdk
Or install from source:
git clone https://github.com/PaperMtn/claude-compliance-sdk.git
cd claude-compliance-sdk
python -m pip install .
Documentation
Full API reference docs are available at papermtn.github.io/claude-compliance-sdk.
Quickstart
Sync
from claude_compliance_sdk import ComplianceClient
with ComplianceClient(api_key="sk-ant-api01-...") as client:
for activity in client.activities.iter(
activity_types=["claude_chat_created", "api_key_created"],
limit=100,
):
print(activity.created_at, activity.type, activity.id)
Async
import asyncio
from claude_compliance_sdk import AsyncComplianceClient
async def main() -> None:
async with AsyncComplianceClient(api_key="sk-ant-api01-...") as client:
async for activity in client.activities.iter(limit=100):
print(activity.created_at, activity.type)
asyncio.run(main())
Every resource group on both clients exposes the same method names —
swap ComplianceClient for AsyncComplianceClient, sprinkle await,
done.
Authentication
Two key types reach the Compliance API, and which you need depends on what you are querying.
| Key type | Created in | Reaches |
|---|---|---|
Compliance Access Key (sk-ant-api01-...) |
claude.ai → Organization settings → API | Every endpoint |
Admin API key (sk-ant-admin01-...) |
Claude Console → Settings → Admin keys | The Activity Feed only — everything else returns 403 |
A Compliance Access Key is created by a primary owner or organisation
owner. A primary owner's key can cover every organisation under the
parent; an organisation owner's key covers their own organisation only.
Admin API keys carry read:compliance_activities only if the
Compliance API was already enabled for the organisation when the key
was created, and cannot be granted any other Compliance scope.
Scopes are chosen at creation and are immutable — to change them, create a new key and delete the old one.
| Scope | Unlocks |
|---|---|
read:compliance_activities |
Activity Feed (activities) |
read:compliance_user_data |
Chats, messages, files, projects, session transcripts, organisation users, group members |
delete:compliance_user_data |
Deleting chats, files, and projects |
read:compliance_org_data |
Organisations, roles, permissions, groups, and effective organisation settings |
Pick the smallest set that works. An audit pipeline that only reads the
feed needs read:compliance_activities. If your workflow both reads
and deletes, use two keys so a leaked read key cannot delete data.
A key with
read:compliance_user_datacan read every chat, file, project, and session transcript in every linked organisation. Treat these keys like production database credentials.
The separate read:compliance_org_settings scope was retired on
2026-06-30. A key carrying only that scope now returns 403 from the
settings endpoint; read:compliance_org_data replaces it.
Authentication and authorisation failures surface as typed exceptions: a
401 (invalid or revoked key) becomes InvalidAPIKeyError, and a 403
becomes PermissionDeniedError — refined to InsufficientScopeError
when the key is valid but missing the scope the endpoint needs. The
403 message names both what the key carries and what the endpoint
wanted, and is available on error_message.
Pass the key when constructing the client:
import os
client = ComplianceClient(api_key=os.environ["ANTHROPIC_COMPLIANCE_ACCESS_KEY"])
Or set the environment variable and let the client read it:
export ANTHROPIC_COMPLIANCE_ACCESS_KEY=sk-ant-api01-...
client = ComplianceClient()
The legacy ANTHROPIC_COMPLIANCE_API_KEY name this SDK shipped with is
still read as a fallback, so existing deployments keep working.
Pagination
Two types of pagination are used:
- Cursor-paginated — Activity Feed, Chats, Messages. Pages carry
first_id/last_id/has_more. - Offset-paginated — everything else. Pages carry
has_moreand an opaquenext_pagetoken.
Every paginated resource exposes both .list() (one page at a time) and .iter() (auto-paginate — yields items one
at a time across all pages) functions.
# .list() — explicit page boundaries
page = client.projects.list(limit=20)
for project in page.data:
print(project.id)
if page.has_more:
next_page = client.projects.list(limit=20, page=page.next_page)
# .iter() — auto-paginate
for project in client.projects.iter(organization_ids=["org_abc123"]):
print(project.id)
Cursor resources are identical in shape; the page contains last_id
and you pass it back as after_id.
Session transcripts
Transcripts of the sessions your users run in Claude apps — Cowork, Claude Code, Claude Science, and Claude for Microsoft 365 — come from two resource groups, split by where the session ran:
| Resource group | Covers | ID prefix |
|---|---|---|
client.local_sessions |
Cowork in Claude Desktop, Claude Code (terminal, desktop, IDE), Claude Science, Claude for Microsoft 365 — all on the user's own machine | clls_ |
client.remote_sessions |
Cowork started on claude.ai web or mobile, running in Anthropic-managed cloud environments | cse_ |
If you are looking for Claude Code usage, it is local_sessions.
with ComplianceClient() as client:
for session in client.local_sessions.iter(created_at_gte="2026-07-01T00:00:00Z"):
if session.product_surface != "claude_code":
continue
for message in client.local_sessions.iter_messages(session.id):
print(session.id, message.role, message.content)
Both groups are read-only — sessions cannot be deleted through the
Compliance API. Transcript content blocks (text, tool_use,
tool_result) are returned as plain dicts so block types that have not
shipped yet pass through rather than breaking parsing. Note that a
tool_use block's input is a JSON-encoded string, and a truncated
one is not valid JSON — raise tool_use_input_max_bytes (or pass -1
for the server maximum) if you need to parse it.
Two errors are worth catching by name. LocalSessionsUnavailableError
is a 404 meaning the endpoints are off for your parent organisation, not
that a session is gone — keep your queued IDs and retry later.
LocalSessionsRetentionUnavailableError is a 503 that is not
transient; skip that session and come back to it on a later run.
Downloads
Three resource groups expose binary content — user files, assistant- generated files, and artifacts. Each provides the same three download methods:
# Into memory, bounded by max_download_bytes (default 100 MiB).
data: bytes = client.files.download("claude_file_xyz789")
# Streamed to disk — unbounded.
client.files.download_to_file("claude_file_xyz789", "/tmp/report.pdf")
# Caller-managed streaming — yields bytes; connection closes when the
# iterator is exhausted or garbage-collected.
for chunk in client.files.download_stream("claude_file_xyz789"):
handle(chunk)
The max_download_bytes cap protects memory on the memory path only.
download_to_file and download_stream ignore the cap and always stream, so you can use them for anything larger than the cap.
client = ComplianceClient(max_download_bytes=10 * 1024 * 1024) # 10 MiB cap
try:
data = client.files.download("claude_file_big")
except FileTooLargeError as exc:
print(f"{exc.size_bytes} bytes > {exc.max_bytes} cap — switching to stream")
client.files.download_to_file("claude_file_big", "big.bin")
User files are deletable (.delete()). Generated files and artifacts
are not.
Rate limits
The API allows 600 requests per minute per parent organisation —
one budget shared across every key beneath it and every
/v1/compliance/* endpoint. The SDK reads the server's
anthropic-ratelimit-* headers on every response and waits for the
stated reset once the budget is spent.
client.activities.list(limit=100)
status = client.rate_limit_status # None until the first response
if status and status.remaining is not None and status.remaining < 50:
... # Slow your workers: the budget is shared with other consumers.
rate_limit_rpm caps how fast this client issues requests. 0
disables that local window; the server-reported budget is still
honoured, because it is not something a caller can opt out of.
The remote session endpoints carry a second budget on top of the shared one, so a 429 there can arrive well below 600 rpm.
Configuration
ComplianceClient and AsyncComplianceClient accept the same kwargs:
| Kwarg | Default | What it does |
|---|---|---|
api_key |
env ANTHROPIC_COMPLIANCE_ACCESS_KEY, then ANTHROPIC_COMPLIANCE_API_KEY |
Compliance Access Key or Admin API key. |
base_url |
https://api.anthropic.com |
Override for testing. |
timeout |
30.0 |
Per-request timeout, seconds. |
max_download_bytes |
100 * 1024 * 1024 |
Eager-download cap. |
max_retries |
3 |
Retry attempts on 429/5xx and connect errors. 0 disables. |
rate_limit_rpm |
600 |
Local burst smoothing for this client. 0 disables the local window. See the note below. |
anthropic_version |
"2023-06-01" |
Sent as the anthropic-version header on every request. None suppresses it. |
On
rate_limit_rpm: this caps how fast a single client issues requests, which matters for a cold burst before the first response arrives. Once responses start coming back, the SDK throttles on the server's ownanthropic-ratelimit-*headers instead, so you no longer need to divide 600 by your worker count. Setting0disables the local window only — the shared server budget is still honoured. See Rate limits.
Contributing
See CONTRIBUTING.md for the dev setup, branch model,
coding conventions, and PR checklist. Architecture decisions worth
preserving live as numbered ADRs under adr/.
License
GPL-3.0-or-later. See LICENSE.
Release files for claude-compliance-sdk 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| claude_compliance_sdk-0.3.0.tar.gz | 67.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| claude_compliance_sdk-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 151.4 kB
Release files / claude_compliance_sdk-0.3.0.tar.gz
| Download URL | claude_compliance_sdk-0.3.0.tar.gz |
|---|---|
| Size | 67.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fca2e422d898469cda9cc29c1ae71dfd742f138d232ef166eb8297abe328ac49
|
|
BLAKE2b-256 checksum How to use checksums |
d19131efa860ba667a5ef9a878a196fa6a1c220388fbe597a3e1885bf4f411b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency logRelease files / claude_compliance_sdk-0.3.0-py3-none-any.whl
| Download URL | claude_compliance_sdk-0.3.0-py3-none-any.whl |
|---|---|
| Size | 84.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
997b77b86fcbb2cdc16abac1c8ff6b4049798a36158efd3602efb44badbd9f27
|
|
BLAKE2b-256 checksum How to use checksums |
d85a2ab2a737928561051964eb1e4edfc3d426f4450ab74c5184d4e6a4242f0a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.
Transparency log