The Compliance API is available only on the Claude Enterprise plan and must be enabled before use. See Get access to the Compliance API.
Required scope: read:compliance_activities on the Compliance Access Key or Admin API key.
A production Compliance API integration makes three design choices: how it consumes the Activity Feed, how its output correlates with your security information and event management (SIEM) system, and where long-term copies of activity and content live. These choices are independent of the endpoints themselves; this page helps you evaluate the tradeoffs.
This page assumes you have read Query the Activity Feed, which defines the parameters and pagination contract referenced throughout, and Retrieve and delete chats, files, and projects, which defines the content endpoints and deleted_at semantics referenced in Plan content retention.
The Activity Feed supports two consumption patterns: periodic window polling bounded by created_at.gte and created_at.lt, and cursor-driven incremental reads that persist a cursor from one response and pass it on the next request. Both return identical Activity objects; the difference is the state your client persists between calls.
Both patterns share these constraints:
limit for each page is 5,000.| Pattern | Choose when |
|---|---|
| Window polling | Your pipeline runs on a fixed schedule, you prefer stateless workers, and you can tolerate replaying or overlapping windows |
| Cursor-driven incremental reads | You want the lowest latency between an activity occurring and your pipeline ingesting it, you want to avoid re-reading pages you already drained, and you have a durable place to persist a cursor between runs |
Set created_at.lt at least 1 minute in the past so that every activity in the window is already queryable. Use created_at.gte for the lower bound and created_at.lt for the upper bound so that consecutive windows tile without gaps or overlap; reuse the previous window's lt value as the next window's gte.
curl --fail-with-body -sS -G \
"https://api.anthropic.com/v1/compliance/activities" \
--header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
--data-urlencode "created_at.gte=2026-04-20T07:00:00Z" \
--data-urlencode "created_at.lt=2026-04-20T08:00:00Z" \
--data-urlencode "limit=5000"When the response has has_more: true, the window contains more than one page of activities. Either page within the window by passing the response's last_id as after_id on the next request (stopping when has_more is false), or choose a smaller time window. See Paginate results for the full contract.
Even with clean tiling, an activity that indexes after its window has closed never appears in a later window. Deduplicate on the activity id and either widen each new window so it overlaps the previous one by a few minutes or run a periodic reconciliation pass that re-queries an older window.
A created_at.lt bound too close to the present silently and permanently drops late-indexed activities: once created_at.gte advances past them, no later window can recover them. Treat the 1-minute queryability figure as the documented indexing lag, not a soft recommendation.
first_id="activity_01XyDMpzjS89pFZXqSFUBDr6" # first_id from a previous response
curl --fail-with-body -sS -G \
"https://api.anthropic.com/v1/compliance/activities" \
--header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
--data-urlencode "limit=5000" \
--data-urlencode "before_id=$first_id"Page through until has_more is false, then persist first_id from the final response and pass it unchanged as before_id on the next run to retrieve activities newer than the saved cursor. To walk in the opposite direction for a backfill, persist last_id and pass it as after_id instead. For the full cursor-vs-page-token reference and retry semantics, see Paginate results.
A production catch-up loop fetches activities recorded since your last poll by driving iteration off has_more and first_id:
cursor = stored_cursor
loop:
page = GET /v1/compliance/activities?before_id={cursor}&limit=5000
store(page.data)
if page.first_id is not null:
cursor = page.first_id
if not page.has_more: break
persist(cursor)Cursors survive key rotation; see Manage and rotate keys.
Each page is adjacent to the cursor you pass: the loop walks forward toward the present, one page at a time. Do not treat a single response as caught up while has_more is true. Persist the cursor only after has_more is false; the unfetched pages are the newer ones between this response's first_id and the present, and they stay unread until you finish the loop or run again.
Each Activity carries fields you can join against events already in your SIEM (Splunk, Datadog, Microsoft Sentinel, Cribl, or similar):
| Compliance API field | Join target |
|---|---|
actor.user_id | Your identity provider's stable user identifier |
actor.email_address | Directory email when a stable ID is unavailable |
actor.ip_address | Network, VPN, and endpoint logs |
created_at | Time-window correlation across any source |
actor.user_id and actor.email_address are present when actor.type is user_actor; check the discriminator before reading them. user_id is a stable, opaque identifier for the user account: it is consistent across every Compliance API endpoint and activity payload, and it does not change when the user's email or display name changes. Use user_id, not email_address, as the primary join key.
Calls to the Compliance API itself emit compliance_api_accessed activities. Ingest these alongside other activity types so your SIEM records who queried compliance data, and when. Filter on actor.type api_actor and actor.api_key_id to attribute each access to a specific Compliance Access Key or Admin API key.
Three retention horizons govern what you can retrieve later:
| Data | Retained for | Controlled by |
|---|---|---|
| Activity Feed records | 6 years | Anthropic |
| Chat, file, and project content | Your organization's claude.ai retention policy | Your organization |
| Content hard-deleted through the Compliance API | Not retained; deletion is immediate and permanent | The caller of the DELETE endpoint |
For how the rest of the Claude Platform handles retention, see API and data retention.
Decide between export-and-archive and on-demand API retrieval as follows:
deleted_at populated, but Compliance API deletes do not.In every other case, rely on direct API retrieval and avoid maintaining a parallel copy.
Treat the Activity Feed as at-least-once: a correctly paginated traversal returns every activity at least once, but a retry after a partial failure can re-deliver activities you already stored. Deduplicate on the activity id field.
The list endpoints do not return a total_count field or a checksum. To attest that an export run is complete, log:
last_id.request-id of the final page.The content endpoints (chats, files, projects, and project attachments) serve claude.ai data only; the Activity Feed surfaces administrative and resource events organization-wide. The Compliance API does not include:
See the Compliance API FAQ for more on what the Compliance API does and does not capture.
For chain of custody, store the exported records with provenance metadata: source endpoint, query parameters, run timestamp, and a content hash of each record.
Filter parameters, pagination, and the Activity object schema.
The content and hard-delete endpoints.
Was this page helpful?