One read of Claude Developer Platformapi-20261110T183715Z
21 pages moved out of 900 read.
What this read moved
1-21 of 21manage-claude/admin-api-keys Changed · +18 / -18 lines
manage-claude/compliance-api-access Changed · +6 / -6 lines
manage-claude/compliance-errors Changed · +20 / -20 lines
manage-claude/compliance-security-posture/check-events-against-results New page · 107 lines, new page
## Run the check ## Match the fields ## Set aside what cannot be compared ## Decide what each mismatch means ## Keep a placeholder where the two sources cannot be matched ## Worked example ## What the check cannot find ## When an organization stops answering
A whole new page. There's nothing to diff it against, so here is what it says.
--- title: Check stored Security posture events against current results url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results description: Once a day, compare the attestation activities your SIEM has stored with the endpoint's current results and decide which mismatches need a person. --- <Note> To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access). </Note> The Activity Feed can deliver an activity late, and the endpoint keeps no history, so each source can show a change that the other does not. A daily comparison finds what your security information and event management (SIEM) store lacks. The feed does not record [every change](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#what-the-feed-does-not-record), so an attestation can be older than the feed’s first activity for its security control, and in rare cases a change has no activity at all. If you only report current results, you do not need the check. You need a Compliance Access Key that covers the organization, with `read:compliance_org_data` for the endpoint and `read:compliance_activities` for the Activity Feed, or `read:org_audit` for both. ## Run the check Start each run after the day’s [daily re-read](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#re-read-15-days-once-a-day) completes, so that late activities are stored. 1. List the linked organizations with [List organizations](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organizations). You get the `uuid` of each. 2. [Call the endpoint](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#request) once for each organization. You get a 200, or a 404 on every run for an organization that the endpoint does not serve (see [Security posture availability](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability)). A 404 means the organization is not read on this run. Keep a list of the organizations that return a 200, each with the `evaluated_at` of its first 200: your first run for the organization. 3. Set aside what the [set-aside rules](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#set-aside-what-cannot-be-compared) list. 4. Group the organization’s remaining stored attestation activities by security control and take the newest by `created_at` for each. You get one activity for each control, or none. 5. For each control that is left, find its row in [the decision table](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#decide-what-each-mismatch-means). You get Match, Expected, or Look into. 6. Act on a Look into only when the next run that reads the organization shows it again; act on row 6 at once, and for rows 10 and 11 follow the [placeholder rules](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#keep-a-placeholder-where-the-two-sources-cannot-be-matched) instead. A run that did not read the organization neither counts nor restarts the wait. Pace your calls and handle a 429 as [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests) describes; an organization whose calls fail after your retries is not read on this run, and a failed call is not a change. ## Match the fields Match an entry in the response to a stored activity with these fields. | In the response | In the activity | How they relate | | ------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `organization_id` | `organization_uuid` | The same value; the activity’s own `organization_id` has the `org_` prefix. | | `controls[].id` | `control` | The same identifier, except as in [rule S2](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#set-aside-what-cannot-be-compared). | | `attestation.attested_at` | `created_at` of the newest `attested`, `changed`, or `renewed` activity | The same time where the response shows the attestation; compare as times, not strings. | | `status` | `status` | While the attestation is in effect, `attested_completed` pairs with `completed`, and `attested_accepted_risk` and `failed_check_accepted_risk` with `accepted_risk`; nothing pairs with `control_failed`. | ## Set aside what cannot be compared Before you compare, set these aside. | # | What | Rule | | -- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | S1 | A stored attestation activity whose `action` is not `attested`, `changed`, `renewed`, `cleared`, or `lapsed` | Leave it out of the whole check; flag each new `action` value for review once. | | S2 | A stored attestation activity that names `mdm_cowork_required_organization` | Count it as one for `mdm_chat_required_organization`. | | S3 | A stored attestation activity whose control has no entry in the response | Nothing to compare; report the control as not in the response, never as Passed (`passed`). | | S4 | An entry whose `status` is `descriptive`, `not_applicable`, or `not_evaluated` | Skip it; a run on which it is `not_evaluated` does not count for that control. | ## Decide what each mismatch means Each control that is left fits exactly one row. | # | Newest stored activity | Entry in the response | Verdict | What to do | | -- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | `attested`, `changed`, or `renewed` | `attested_at` equals its `created_at`; `state` is `in_force`; `status` pairs with its value. | Match | Nothing. | | 2 | `cleared` | `attestation` is `null`, except as in row 11. | Match | Nothing. | | 3 | `lapsed`, with Accepted risk (`accepted_risk`) | `attestation` is `null` or has the earlier activity’s time with `state` `check_passing` or `setting_changed`. | Match | Nothing. | | 4 | `lapsed`, with `completed` or `control_failed` | `attestation` is `null`. | Match | Nothing. | | 5 | `attested`, `changed`, or `renewed` | `attested_at` equals its `created_at`; `state` is `review_due`, `check_passing`, or `setting_changed`. | Expected | Not in effect: act once on each new state, without waiting for an activity; a return to `in_force` resets this. | | 6 | `attested`, `changed`, or `renewed`, with Completed (`completed`) and a `created_at` later than your first run | On the first run that compares the activity, `attestation` is `null`, and `status` is `failed` with a `current_value`. | Look into | The Security posture page may show a failing check as Passed: flag for review, with no wait. | | 7 | `attested`, `changed`, or `renewed`, with `completed` | `attestation` is `null`; `status` is neither `not_attested` nor `failed` with a `null` `current_value`; row 6 does not fit. | Expected | Nothing to compare; the response never shows it. | | 8 | `attested`, `changed`, or `renewed`, as Failed (`control_failed`) | `attestation` is `null`; `status` is one of three: `failed`; any status that the automatic check gives; or, from the end date (`review_date`, in UTC) on, `not_attested`. | Expected | Nothing to compare; act once when `status` leaves `failed` from the end date on. | | 9 | `attested`, `changed`, or `renewed`, with `accepted_risk` | `attestation` is `null`, and `status` is `passed`, `matches_profile`, or `exceeds_baseline`. | Expected | Store a placeholder ([placeholder rule 7](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#keep-a-placeholder-where-the-two-sources-cannot-be-matched)). | | 10 | None, or every stored activity is older than `attested_at` | `attestation` is present. | Look into | Follow the placeholder rules. | | 11 | None, or one whose value is not `control_failed` | `current_value` is `null`, and `status` is `failed`. | Look into | Your store lacks an attestation as Failed (`control_failed`): follow the placeholder rules and act once when `status` leaves `failed`. | | 12 | `attested`, `changed`, `renewed`, or `cleared`, newer than `attested_at`, with another activity from almost the same time | `attestation` is present. | Expected | Changes made at almost the same time can be stored in either order. | | 13 | The same, with no such second activity | `attestation` is present. | Look into | Contact Anthropic support, once. | | 14 | `attested`, `changed`, or `renewed` | `attested_at` equals its `created_at`; `state` is `in_force`; `status` does not pair with its value. | Look into | Contact Anthropic support, once. | | 15 | `attested`, `changed`, or `renewed`; no earlier row fits | `attestation` is `null`. | Look into | Most likely cleared: store a placeholder ([placeholder rule 7](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results#keep-a-placeholder-where-the-two-sources-cannot-be-matched)) and flag for review once. | | 16 | None | `attestation` is `null`, and row 11 does not fit. | Match | Nothing. | | 17 | Any other | Any other. | Look into | Flag for review once. | ## Keep a placeholder where the two sources cannot be matched A placeholder stands in for what one of the two sources lacks, and you keep it apart from your stored activities. For rows 10 and 11, read the feed again, and store and flag the placeholder only if nothing arrives within 15 days, the reach of the [daily re-read](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#re-read-15-days-once-a-day). On your first run, store it at once, with no review. Row 10 placeholders, keyed on the control and `attested_at`: 1. Read again from your newest stored activity for the control, or from `attested_at` inclusive if you have stored none; the 15 days count from `attested_at`. Build the placeholder from the entry, marked as having no activity; in the decision table, read it as an `attested` activity at that `attested_at` whose value pairs with its `status`, if any. 2. On each run that shows the attestation, update its `status` and `state`. 3. When an activity arrives whose `created_at` equals that `attested_at`, replace the placeholder with it. 4. When two runs in a row do not show the attestation, resolve the placeholder; flag that for review unless a newer stored activity or an unresolved row 10 mismatch for the control explains it, or both runs show `descriptive`. 5. A run that did not read the organization, or shows `not_evaluated`, neither counts toward nor restarts those two runs. 6. If the attestation shows again, reopen the same placeholder. Row 9, 11, and 15 placeholders, keyed on the control alone: 7. For row 11, the 15 days count from the first run that shows the `status`. While the placeholder is unresolved, flag nothing more for that control; resolve it when a newer activity arrives, the attestation shows, or two runs in a row fit another row. 8. When a row 9 placeholder resolves because the attestation shows as `failed_check_accepted_risk`, flag it for review once: the risk is in effect. ## Worked example These two runs read the organization in the [response sample](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#response) on the Results reference; run 1 is your first run. * Run 1, `directory_sync_enabled`. Stored: `attested`, `accepted_risk`, created at `2026-10-20T15:04:00.220114Z`. Response: `failed_check_accepted_risk`, `in_force`, the same `attested_at`. Row 1: Match. * Run 1, `allowed_invite_domains`. Stored: nothing. Response: `descriptive`, `attestation` `null`. Rule S4: set aside. * Run 1, `oauth_conditional_access`. Stored: nothing. Response: an `attestation` with `state` `review_due`. Row 10: Look into. On your first run, store a placeholder at once, with no review. * Run 2, `oauth_conditional_access`. Placeholder: the one from run 1. Response: the same. Row 5: Expected. Act once on `review_due`. ## What the check cannot find The daily check cannot find a missing activity for an attestation that the response leaves out on an automatic control. The response gives no sign of such an attestation, or only the `status` `failed`, which looks like the status the automatic check gives. ## When an organization stops answering An organization that has returned a 200 and then returns a 404 on several runs in a row needs a person, once. Ask someone with access to the Security posture page whether the page was turned off for the organization (see [Security posture availability](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability)). If the page was not turned off, contact your Anthropic representative. The organization might have been deleted, or your access, Security posture, or the endpoint might have ended for the organization. Whatever the cause, resolve the organization’s placeholders and unresolved mismatches with no review, keep calling the organization, and reopen them if the organization returns a 200.
manage-claude/compliance-security-posture/detect-changes New page · 99 lines, new page
## Before you write a rule ## Attestation rules ### A risk was accepted ### A control was attested as Failed ### Someone outside an allowlist changed an attestation ### One person made many attestation changes ### An attestation ended automatically ## Keep rules working as values change ## Test a rule
A whole new page. There's nothing to diff it against, so here is what it says.
--- title: Detect changes in Security posture url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes description: "Start from sample detection rules for Security posture activities in your SIEM: accepted risks, controls attested as Failed, unexpected editors, bursts of changes, and attestations that end automatically." --- <Note> To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access). </Note> These sample rules alert on changes in your organization’s [Security posture](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview), using the activities that the Compliance API Activity Feed records. They assume that your security information and event management (SIEM) system stores these activities, as [Send events to your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events) describes. ## Before you write a rule Each rule is a plain description and a query in no particular query language. * Queries use the Activity Feed’s field names, plus `stored_at`, this page’s name for when you stored an activity. Any other name is your own list or alias. * Before a rule counts activities, deduplicate them by `id`. * Unless a rule says otherwise, run it over the time since its last completed run, by `stored_at`, not `created_at`, because an activity can arrive late; queries leave that range out. * Write rules that fire on an activity you stored, never on one you have not: it may be late or a change [the feed does not record](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#what-the-feed-does-not-record). To compare stored activities with current results, see [Check events against results](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results). ## Attestation rules These five rules read [`org_security_control_attestation_updated`](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#attestation-activity) activities. ### A risk was accepted Alert when someone accepts the risk (`accepted_risk`) of not meeting a security control, so that a second person can review the decision. ```sql type == "org_security_control_attestation_updated" AND status == "accepted_risk" AND actor.type != "system_actor" ``` The rule leaves out a `system_actor`, because an automatic change, such as an attestation that ended (`lapsed`), keeps the `status` but is not an acceptance. ### A control was attested as Failed Alert when someone attests to a control as Failed (`control_failed`), so that someone follows up on the control. ```sql type == "org_security_control_attestation_updated" AND status == "control_failed" AND actor.type != "system_actor" ``` The rule leaves out a `system_actor` for the same reason as [A risk was accepted](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes#a-risk-was-accepted). ### Someone outside an allowlist changed an attestation Alert when an attestation is recorded, changed, saved again, or cleared by someone not on your list of people who manage attestations. Keep their `user_id` values (`allowed_user_ids`) in your SIEM. ```sql type == "org_security_control_attestation_updated" AND actor.type != "system_actor" AND NOT (actor.type == "user_actor" AND actor.user_id IN allowed_user_ids) ``` * Any actor other than a listed `user_actor` or a `system_actor` fires the rule. * Key the list on `actor.user_id`: `actor.email_address` is the address the person had when the activity was recorded ([Correlate with your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#correlate-with-your-siem)). ### One person made many attestation changes Alert when one person makes more attestation changes in a short time than is usual for your organization. The threshold of 10 and the 1-hour window are examples; choose both from your own activity. ```sql type == "org_security_control_attestation_updated" AND actor.type == "user_actor" | group by organization_uuid, actor.user_id over a sliding 1 hour of created_at | where count(distinct id) >= 10 ``` * Alert only for a group that holds an activity stored since the rule’s last run, and count over every activity that you stored, so that a late activity joins a burst whose other activities you stored earlier. * Counting by `created_at` measures the person’s pace, not your ingestion’s. ### An attestation ended automatically Treat a `lapsed` activity as a prompt to review the control that it names. ```sql type == "org_security_control_attestation_updated" AND action == "lapsed" ``` A [`lapsed` activity](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#what-a-lapsed-activity-means) means that the control’s check result or its current value differs from the one the attestation was saved on, not that an end date (`review_date`) passed. It can come late. ## Keep rules working as values change New values can appear in any of these fields. * Identify automatic changes by `actor.type`, not by the value of `actor.service`. * Do not drop activities whose `control`, `action`, or `status` value a rule does not list; a new `action` value can record an acceptance. See the [events reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference). ## Test a rule To see [the allowlist rule](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes#someone-outside-an-allowlist-changed-an-attestation) fire, choose someone who can attest and who is not on your list. Have that person attest to a control that has no attestation and whose result no one relies on, then clear it. Until it is cleared, the attestation can change that control’s result. Both activities can take a while to reach the Activity Feed. If you store these activities as Open Cybersecurity Schema Framework (OCSF) events, [Map Security posture events to OCSF](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/ocsf-mapping) maps their fields.
manage-claude/compliance-security-posture/events-reference New page · 81 lines, new page
## Attestation activity ### Fields ### `action` values ### What a `lapsed` activity means ### Example ## What the feed does not record
A whole new page. There's nothing to diff it against, so here is what it says.
---
title: Security posture events reference
url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference
description: "Look up the Activity Feed activities that record changes on the Security posture page: their fields and values, an example of each, and what the feed does not record."
---
<Note>
To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
</Note>
The [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) records changes to attestations on the [Security posture](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview) page as the activities that this page describes. To ingest them into a security information and event management (SIEM) system, start at [Send Security posture events to your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events). Pass through any value of `control`, `action`, or another field that this page does not list, ignore unexpected fields, and treat a missing key and a `null` value alike. [Understand the Activity object](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#understand-the-activity-object) covers the standard fields and unknown types.
You need a Compliance Access Key that covers the organization, with the `read:compliance_activities` or `read:org_audit` scope.
## Attestation activity
An `org_security_control_attestation_updated` activity records that someone recorded, changed, saved again, or cleared the organization’s attestation for a security control, or that the attestation ended automatically. Its `created_at` is the time of a person’s change or, for an automatic one, the time at which the change was recorded, which can be later than the change. Its `actor` is a `user_actor` for a person’s change and a `system_actor` for an automatic one, such as `lapsed`.
### Fields
This type adds the following fields, where `status` is the attestation’s value and `review_date` is its end date.
| Field | Type | Description |
| ----------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `control` | string | The identifier of the security control that the attestation applies to, for example, `oauth_conditional_access`; treat it as an opaque string. |
| `action` | string | What changed, as one of the [`action` values](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#action-values). |
| `status` | string | The attestation’s value: Completed (`completed`), Accepted risk (`accepted_risk`), or attested as Failed (`control_failed`); absent when the attestation was cleared. |
| `previous_status` | string | The attestation’s value before this change, one of the same three; absent when `action` is `attested`. |
| `review_date` | string | The UTC day (ISO 8601 date) on which the attestation is due to end; absent if it was saved with no end date or cleared. |
On an information-only control, the value Reviewed is recorded as `completed`.
### `action` values
| `action` | Meaning |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `attested` | An attestation was recorded for a control that had none. |
| `changed` | An attestation was saved again with another value or, where `status` equals `previous_status`, with the same value, as with `renewed`. |
| `renewed` | An attestation was saved again with the same value. |
| `cleared` | A person cleared an attestation. |
| `lapsed` | An attestation ended automatically, not by a person. |
On `renewed` and `lapsed` activities, `status` equals `previous_status`. A save with the same value after a `lapsed` activity is recorded as `renewed`, not `attested`.
### What a `lapsed` activity means
A `lapsed` activity means that the check result or the control’s current value differs from the one the attestation was saved against; the current value can change with no setting changed, for example when Anthropic rewords it. `status` is the value that ended: any of the three. An attestation of a manual control never gets a `lapsed` activity. The activity can come later than the change that caused it.
### Example
```json
{
"id": "activity_01Hq7ZtYc4Vb2NmKx8RsPd3W",
"type": "org_security_control_attestation_updated",
"created_at": "2026-10-20T15:04:00.220114Z",
"organization_id": "org_01JuY4bkwkH1x4PodBJaWmh2",
"organization_uuid": "91012d09-e48b-438e-a489-1bebfd8fa6f9",
"actor": {
"type": "user_actor",
"email_address": "[email protected]",
"user_id": "user_01WxYzAbCdEfGhJkMnPqRsTu",
"ip_address": "192.0.2.34",
"user_agent": "Mozilla/5.0..."
},
"control": "directory_sync_enabled",
"action": "attested",
"status": "accepted_risk"
}
```
## What the feed does not record
Do not read the absence of an activity as a sign that nothing changed. For current results, see [Security posture results reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference); its endpoint can omit a control that an activity names.
* Changes from before the [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) began recording these activities for the organization, or while the Compliance API was off, never added later.
* Rarely, a change of any kind.
* Every end date that arrives: not all get an activity, so do not wait for one.
* Each time the Security posture page is turned off or on: do not rely on a [detection rule](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes) to detect it.
* Comments saved with an attestation, or any mark that one exists. Changing a comment takes a new save, which the feed records like any other save with the same value (see [`action` values](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#action-values)).
* Which kind of control an attestation is for: automatic, manual, or information-only.
* Every change that could end an attestation: not all get a `lapsed` activity.
manage-claude/compliance-security-posture/ocsf-mapping New page · 120 lines, new page
## OCSF version ## Attributes for every Security posture activity ## Attestation activities: Entity Management
A whole new page. There's nothing to diff it against, so here is what it says.
---
title: Map Security posture events to OCSF
url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/ocsf-mapping
description: Map each Security posture activity in the Compliance API to its Open Cybersecurity Schema Framework (OCSF) class and attributes before you store it.
---
<Note>
To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
</Note>
The [Open Cybersecurity Schema Framework](https://schema.ocsf.io/) (OCSF) is an open schema for security events. Apply this mapping to [Security posture](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview) activities in your own pipeline, after you read them and before you store them. To ingest them into your security information and event management (SIEM) system, start at [Send Security posture events to your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events).
## OCSF version
This mapping uses OCSF 1.6.0. If you validate against another version, check the attributes on this page against that version. For example, in OCSF 1.7.0, `metadata.uid` is the identifier of the OCSF event itself, and `metadata.original_event_uid` holds the identifier from the source. OCSF 1.9.0 deprecates `actor.app_name` in favor of `actor.application`.
## Attributes for every Security posture activity
Map these fields on every event.
| Activity field | OCSF attribute | Note |
| ------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `metadata.uid` | Copy unchanged. |
| `type` | `metadata.event_code` | Copy unchanged. |
| `created_at` | `time` | Convert the RFC 3339 string to milliseconds since the Unix epoch and truncate to a whole number. |
| `created_at` | `metadata.original_time` | Copy the string unchanged. |
| None | `metadata.logged_time` | The time at which you stored the activity (`stored_at` on [Detect changes](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes#before-you-write-a-rule)), in milliseconds since the Unix epoch. |
| `organization_uuid` | `metadata.tenant_uid` | Copy unchanged. |
| `organization_id` | `unmapped.organization_id` | Copy unchanged. |
| None | `metadata.version` | Constant: `1.6.0`. |
| None | `metadata.product.vendor_name` | Constant: `Anthropic`. |
| None | `metadata.product.name` | Constant: `Compliance API`. |
| None | `type_uid` | `class_uid * 100 + activity_id`. |
| None | `severity_id` | Set to `1` (Informational) on every event and set an alert’s priority in the [detection rule](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes) that raises it. |
Put every field that has no OCSF attribute in the `unmapped` object under its Activity Feed name, including fields that your handler does not recognize. Where a field is absent or `null`, leave out the OCSF attribute.
Map the `actor` object:
| Activity field | OCSF attribute | Note |
| --------------------- | ------------------------- | ------------------------------------------------------------------------------ |
| None | `metadata.profiles` | Add `host`, the OCSF profile (an optional attribute set) that carries `actor`. |
| `actor.type` | `unmapped.actor.type` | Copy unchanged. |
| `actor.user_id` | `actor.user.uid` | `user_actor` only. |
| `actor.email_address` | `actor.user.email_addr` | `user_actor` only. |
| `actor.ip_address` | `src_endpoint.ip` | `user_actor` only. |
| `actor.user_agent` | `http_request.user_agent` | `user_actor` only. |
| `actor.service` | `actor.app_name` | `system_actor` only. |
## Attestation activities: Entity Management
Map an [`org_security_control_attestation_updated`](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#attestation-activity) activity to the OCSF Entity Management class (3004). Entity Management events report an operation on a managed entity, here the organization’s attestation for a security control.
| Activity field | OCSF attribute | Note |
| ----------------- | -------------------------- | -------------------------------------------------------------------- |
| None | `class_uid` | Constant: `3004` (Entity Management). |
| None | `category_uid` | Constant: `3` (Identity & Access Management). |
| `action` | `activity_id` | From the table of `action` values that follows. |
| `action` | `unmapped.action` | Copy unchanged, because two `action` values share one `activity_id`. |
| None | `entity.type_id` | Constant: `99` (Other). |
| None | `entity.type` | Constant: `Security control attestation`. |
| `control` | `entity.uid` | Copy unchanged. |
| `status` | `entity.data.status` | Copy unchanged: the attestation’s value. |
| `review_date` | `entity.data.review_date` | Copy unchanged: the attestation’s end date. |
| `previous_status` | `unmapped.previous_status` | Copy unchanged: the attestation’s value before the change. |
Do not map `status` to `status_id` or to any pass or fail value: an attestation is a person’s statement about a control, not the result of a check.
| `action` | `activity_id` | `type_uid` |
| --------------- | ----------------- | ---------- |
| `attested` | `1` (Create) | `300401` |
| `changed` | `3` (Update) | `300403` |
| `renewed` | `3` (Update) | `300403` |
| `cleared` | `4` (Delete) | `300404` |
| `lapsed` | `11` (Deactivate) | `300411` |
| Any other value | `99` (Other) | `300499` |
For `99` (Other), set `activity_name` to the `action` value.
An `attested` activity maps to an event like this one, with sample values:
```json
{
"class_uid": 3004,
"category_uid": 3,
"activity_id": 1,
"type_uid": 300401,
"severity_id": 1,
"time": 1794495872517,
"metadata": {
"version": "1.6.0",
"profiles": ["host"],
"uid": "activity_01Kp5RvNd8Wc3TgMy6BxQf4Z",
"event_code": "org_security_control_attestation_updated",
"original_time": "2026-11-12T15:04:32.517208Z",
"logged_time": 1794495910000,
"tenant_uid": "91012d09-e48b-438e-a489-1bebfd8fa6f9",
"product": { "vendor_name": "Anthropic", "name": "Compliance API" }
},
"actor": {
"user": {
"uid": "user_01TuVwXyZaBcDeFgH2JkLmN4",
"email_addr": "[email protected]"
}
},
"src_endpoint": { "ip": "192.0.2.34" },
"http_request": { "user_agent": "ExampleBrowser/1.0" },
"entity": {
"type_id": 99,
"type": "Security control attestation",
"uid": "mdm_chat_required_organization",
"data": { "status": "completed" }
},
"unmapped": {
"action": "attested",
"actor": { "type": "user_actor" },
"organization_id": "org_01JuY4bkwkH1x4PodBJaWmh2"
}
}
```
manage-claude/compliance-security-posture/overview New page · 120 lines, new page
## Choose your path ## What Security posture evaluates ### Controls ### Attestations ### Results ### What ends an attestation ## Changes over time: the Activity Feed ## Current results: the endpoint ## Availability ## Who can see who attested ## What Anthropic stores when someone attests
A whole new page. There's nothing to diff it against, so here is what it says.
--- title: Security posture in the Compliance API url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview description: Understand what the Compliance API exposes about the Security posture page (Security Center) in claude.ai and where to start. --- <Note> To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access). </Note> The **Security posture** page in claude.ai **Organization settings** compares your organization’s Claude settings with Anthropic’s recommended security controls. Through the Compliance API, your security tools can read the changes that the page records. They can also read current results. Security posture reports on your settings and does not change them. The sidebar item is **Security posture**, and the page it opens is headed **Security Center**. ## Choose your path To get changes on the page into your security information and event management (SIEM) system, start with [Send Security posture events to your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events). If you already ingest the whole Activity Feed, you have them; [check two things](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#if-you-already-ingest-the-full-feed). * To alert on risky changes, see [Detect changes in Security posture](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes). * To normalize to the Open Cybersecurity Schema Framework (OCSF), see [Map Security posture events to OCSF](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/ocsf-mapping). * To find who accepted which risk, when, and until when, see [Security posture events reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference); for risks in effect, see [Current results](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#current-results). To work with current results from the endpoint, use these pages: * For dashboards, see [Security posture results reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference). * To verify stored events, see [Check stored Security posture events against current results](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results). * If the endpoint and the page disagree, see [How an attestation shows in the response](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#how-an-attestation-shows-in-the-response). To understand the data, read on. ## What Security posture evaluates Security posture evaluates a list of controls and gives each one a result. ### Controls A control is one recommended setting or practice, such as single sign-on. Each control has a display name and an identifier. The identifier is the same for every organization. A control can also have a current value (`current_value`) and a recommended value (`desired_state`). Controls come in three kinds: | Kind | What decides its result | Example | | ------------------------ | ----------------------------------------------------------------------------------------------------------- | -------------------------- | | Automatic control | An automatic check of the current value against the recommended value, unless an attestation is in effect. | `sso_enabled` | | Manual control | A person, because Anthropic cannot read the setting, for example when it lives in another vendor’s console. | `oauth_conditional_access` | | Information-only control | Nothing: there is no recommended value, so the control is reported and not rated. | `allowed_invite_domains` | ### Attestations An attestation is a person’s recorded statement of how the organization stands on a control; it is not the result of a check. Most controls can carry an attestation, automatic ones included, whatever their check’s result. An attestation has one of three values: * Completed (`completed`): the control is in place. * Accepted risk (`accepted_risk`): the control is not in place, and the organization accepts the risk. * Failed (`control_failed`): the control is not in place. Someone who can attest does so on the page. The API reads attestations and cannot make them. The page can ask a question when someone attests, sometimes requiring an answer, and stores the answer with the attestation as its [comment](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#what-anthropic-stores-when-someone-attests), up to 2,000 characters. An Activity Feed activity never includes the comment or shows that one exists. The endpoint returns no comments either. ### Results Each control has one of four results. | Result | Meaning | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | Passed (`passed`) | Meets the recommended value, or an attestation of Completed or Accepted risk is in effect. | | Failed (`failed`) | Does not meet the recommended value or is attested as Failed (`control_failed`). | | Not attested (`not_attested`) | A manual control with no attestation in effect. | | Descriptive (`descriptive`) | Not rated, even when attested; it covers information-only controls and controls that do not apply or could not be read. | An accepted risk in effect counts as Passed on an automatic or manual control, though the control is not in place. In the response, an automatic control [attested as Completed while its check fails](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#how-an-attestation-shows-in-the-response) is `failed`. ### What ends an attestation An attestation stays in effect until one of three things happens: * Someone clears or changes it. * Its end date (`review_date`) arrives. The person who attests picks 90 days or none. * On an automatic or information-only control, the current value changes, or, for an accepted risk on some automatic controls, the check passes. Without an attestation in effect, an automatic control’s result follows its check, and a manual control is Not attested. ## Changes over time: the Activity Feed The Activity Feed answers what changed, when, and who changed it. It records an activity when someone attests to a control, changes an attestation, or clears one, and sometimes when one ends automatically. These pages’ titles call the activities events. Reading them takes the `read:compliance_activities` or `read:org_audit` scope. [Security posture events reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference) lists their fields. To collect them, see [Send Security posture events to your SIEM](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events). ## Current results: the endpoint The endpoint answers what a control’s result is at the time of the request. Use it to report across the organizations under your [parent organization](https://platform.claude.com/docs/en/manage-claude/compliance-api#how-the-compliance-api-works). Each call reads one organization and returns no history. For each control it lists, the response gives its `id`, `display_name`, and result in `rating`, using the identifiers in the [results table](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#results). Calling it takes the `read:compliance_org_data` or `read:org_audit` scope. The page, the endpoint, and the feed do not always show the same thing, because the response leaves out some controls and some attestations. See [How an attestation shows in the response](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#how-an-attestation-shows-in-the-response) and [Check stored Security posture events against current results](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/check-events-against-results). ## Availability Security posture is in beta. **If your organization is on Claude Enterprise, Security posture is available to it, and its parent organization has the Compliance API enabled,** the Activity Feed records attestation activities for it, and the endpoint returns your organization’s results. You also need a Compliance Access Key with the matching scope. These pages assume you have read [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access) and [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed). **If your organization is on another plan or is a Claude Console organization,** the Activity Feed records no Security posture activities for it, and the endpoint returns 404. **If the Security posture page has been turned off for your organization,** the endpoint returns 404 for your organization until the page is turned on. Even a key for the parent organization gets that 404. For some organizations, the endpoint returns 404 even when all three conditions hold and the page has not been turned off. ## Who can see who attested Each attestation activity that a person caused records their user ID, their email address at the time, and the request’s IP address and user agent. Any key that covers the organization and holds `read:compliance_activities` or `read:org_audit` can read them, even after they leave the organization or their account is deleted. Deleting the organization does not remove these activities from the Activity Feed, which retains activities for 6 years. The organization’s own keys stop working when it is deleted. Any key with both `read:compliance_org_data` and `read:compliance_user_data`, or `read:org_audit`, can read, in the endpoint’s `attested_by`, the user ID of the person who attested, where the endpoint returns it, even for attestations made before you had access. These values are personal data; your copies outlive the person’s membership. Before you collect this data, tell the people who attest. ## What Anthropic stores when someone attests Anthropic stores one attestation per control, including the value, when it was made, any end date, and the account of the person who attested. Attesting again replaces it. Anthropic keeps storing an attestation after its end date arrives or it [ends automatically](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#what-ends-an-attestation), until someone clears it or Anthropic deletes it with the organization. If the account of the person who attested is deleted, Anthropic keeps storing the attestation, which no longer says who attested. Any Activity Feed activities that this person caused still name them. Clearing or replacing the attestation removes nothing from the Activity Feed (see [Who can see who attested](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#who-can-see-who-attested)). [Customer-managed encryption keys (CMEK)](https://platform.claude.com/docs/en/manage-claude/cmek), [zero data retention (ZDR) for Claude Code](https://code.claude.com/docs/en/zero-data-retention), and a [HIPAA-ready Enterprise plan](https://support.claude.com/en/articles/13296973-hipaa-ready-enterprise-plans) do not change what Anthropic stores of an attestation’s control, value, dates, and account. None of the three shortens how long Anthropic stores them. CMEK does not encrypt these fields. Anthropic stores an attestation’s comment until someone clears the attestation or Anthropic deletes the comment with the organization. Attesting again can replace or remove the comment. While Security posture is not available to an organization, Anthropic keeps storing its attestations and comments, and nobody can see or clear them on the Security posture page. A custom conversation retention period does not shorten how long Anthropic stores the attestation or the comment. Activity Feed activities never include the comment (see [What the feed does not record](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#what-the-feed-does-not-record)).
manage-claude/compliance-security-posture/results-reference New page · 271 lines, new page
## Request ## Response ### Top-level fields ### `controls[]` fields ### `attestation` fields ### `attested_by` fields ## Status values ## Attestation states ## How an attestation shows in the response ## Count results ## Who attested, and comments ## Errors ## Freshness and side effects
A whole new page. There's nothing to diff it against, so here is what it says.
---
title: Security posture results reference
url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference
description: "Look up the Compliance API endpoint that returns an organization's current Security posture results: the request, the response fields, what each status means, and the errors."
---
<Note>
To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
</Note>
This endpoint returns an entry for most of an organization’s security controls, evaluated at the time of the request, with the [Security posture attestation](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#attestations) that the response shows for each control. You need a Compliance Access Key that covers the organization, with the `read:compliance_org_data` or `read:org_audit` scope; [Security posture availability](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability) says which organizations can be read.
## Request
Send a `GET` request to `/v1/compliance/organizations/{organization_id}/security_posture`. Each call reads one organization, and the response is not paginated.
```bash cURL
curl --fail-with-body -sS \
"https://api.anthropic.com/v1/compliance/organizations/91012d09-e48b-438e-a489-1bebfd8fa6f9/security_posture" \
-H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
-H "anthropic-version: 2026-10-21"
```
| Item | Rule |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organization_id` | The `uuid` of a [linked organization](https://platform.claude.com/docs/en/manage-claude/compliance-api#how-the-compliance-api-works) from [List organizations](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organizations); any other value returns 404. |
| Key | A [key for the parent organization](https://platform.claude.com/docs/en/manage-claude/compliance-api-access#set-up-the-compliance-api) can name any linked organization, and a key for a single organization can name only that organization. |
| `anthropic-version` | Required; a request without it returns 400. |
| Query parameters | None; a request with any query parameter returns 400. |
## Response
The following abridged example shows four of the controls that a response can contain. It is the response to a key that holds `read:compliance_org_data` and `read:compliance_user_data`.
```json Response
{
"type": "security_posture",
"organization_id": "91012d09-e48b-438e-a489-1bebfd8fa6f9",
"evaluated_at": "2027-02-09T09:00:02.417305Z",
"comments_status": "not_enabled",
"controls": [
{
"id": "sso_enabled",
"display_name": "Single sign-on (SSO)",
"section": "identity_access",
"setting_name": "sso_enabled",
"status": "passed",
"rating": "passed",
"current_value": "On",
"desired_state": "On",
"attestation": null
},
{
"id": "directory_sync_enabled",
"display_name": "Directory sync (SCIM)",
"section": "identity_access",
"setting_name": "directory_sync_enabled",
"status": "failed_check_accepted_risk",
"rating": "passed",
"current_value": "Off",
"desired_state": "On",
"attestation": {
"state": "in_force",
"attested_at": "2026-10-20T15:04:00.220114Z",
"comment": null,
"attested_by": {
"type": "user_actor",
"user_id": "user_01WxYzAbCdEfGhJkMnPqRsTu"
}
}
},
{
"id": "allowed_invite_domains",
"display_name": "Allowed email domains",
"section": "identity_access",
"setting_name": "allowed_invite_domains",
"status": "descriptive",
"rating": "descriptive",
"current_value": "example.com",
"desired_state": null,
"attestation": null
},
{
"id": "oauth_conditional_access",
"display_name": "OAuth conditional access on connected SaaS",
"section": "connectors_integrations",
"setting_name": null,
"status": "not_attested",
"rating": "not_attested",
"current_value": null,
"desired_state": "Completed",
"attestation": {
"state": "review_due",
"attested_at": "2026-11-02T09:30:00.008771Z",
"comment": null,
"attested_by": {
"type": "user_actor",
"user_id": "user_01AbCdEfGhJkLmNpQrStUvWx"
}
}
}
]
}
```
Every field is always present, and a field with no value is `null`, never left out. A time has either no fractional digits or six, so compare times as times, not as strings.
### Top-level fields
| Field | Type | Description |
| ----------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | string | Always `security_posture`. |
| `organization_id` | string | The organization’s UUID. |
| `evaluated_at` | string (RFC 3339, UTC) | The time at which every control was evaluated. |
| `comments_status` | string | Whether attestation comments were read; see [Who attested, and comments](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#who-attested-and-comments). |
| `controls` | array of objects | The organization’s controls, never empty. |
### `controls[]` fields
| Field | Type | Description |
| --------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | string | The control’s identifier, which is the same for every organization and never changes. |
| `display_name` | string | The control’s display name, as English display text whose wording can change. |
| `section` | string | The section that the control belongs to, one of the ten listed after this table; more values can be added, so treat an unknown one as a section of its own. |
| `setting_name` | string or null | The `name` of the entry in the organization’s effective settings that this control reads; `null` when it reads no such entry. |
| `status` | string | The reason for the control’s result; see [Status values](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#status-values). |
| `rating` | string | The control’s result, which follows from `status`; see [Status values](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#status-values). |
| `current_value` | string or null | The current value, as English display text whose wording can change; `null` on a manual control or when no value was read. |
| `desired_state` | string or null | The recommended value, as English display text whose wording can change; `null` when there is none for this organization. |
| `attestation` | object or null | The attestation that the response shows, also while it is not in effect; `null` while `status` is `descriptive`, `not_applicable`, or `not_evaluated`, and in [these cases](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#how-an-attestation-shows-in-the-response). |
`section` is one of `identity_access`, `data_privacy`, `capabilities`, `connectors_integrations`, `chats_desktop_mdm`, `cowork_admin_console`, `cowork_desktop_mdm`, `claude_code_admin_console`, `claude_code_managed_settings`, and `healthy_adoption`.
To compare values in code, look up `setting_name` in the [effective settings](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#get-effective-organization-settings) of the same organization. The lookup can find nothing, and two controls can share one `setting_name`.
### `attestation` fields
| Field | Type | Description |
| ------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state` | string | Whether the attestation is in effect; see [Attestation states](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference#attestation-states). |
| `attested_at` | string (RFC 3339, UTC) | When the attestation was made. |
| `comment` | string or null | The comment saved with the attestation, of at most 2,000 characters; `null` if there is none or if `comments_status` is not `available`. |
| `attested_by` | object or null | The person who attested; `null` when the key holds neither `read:compliance_user_data` nor `read:org_audit`, when that person’s account has been deleted or is being deleted, or when the endpoint does not return who attested for the organization. |
### `attested_by` fields
| Field | Type | Description |
| --------- | ------ | ----------------------------------------- |
| `type` | string | Always `user_actor`. |
| `user_id` | string | The user’s ID, which starts with `user_`. |
## Status values
`status` gives the reason for a control’s result, and each status has one `rating`.
| `status` | Kind of control | Meaning | `rating` | On the page |
| ---------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------ | -------------- | -------------------------------------------------------- |
| `passed` | automatic | The current value meets the recommended value. | `passed` | Passed |
| `matches_profile` | automatic | The current value equals the recommended value. | `passed` | Passed |
| `exceeds_baseline` | automatic | The current value is stricter than the recommended value. | `passed` | Passed |
| `failed_check_accepted_risk` | automatic | The automatic check fails, and an accepted risk is in effect. | `passed` | Passed |
| `failed` | automatic or manual | The current value does not meet the recommended value, or an attestation that the response leaves out gives this result. | `failed` | Failed, or Passed with a Completed attestation in effect |
| `review` | automatic | The current value is looser than the recommended value. | `failed` | Failed |
| `attested_completed` | manual | An attestation with the value Completed (`completed`) is in effect. | `passed` | Passed |
| `attested_accepted_risk` | manual | An attestation with the value Accepted risk (`accepted_risk`) is in effect. | `passed` | Passed |
| `not_attested` | manual | No attestation is in effect. | `not_attested` | Not attested |
| `attestation_not_enabled` | manual | Nobody can attest to the control. | `not_attested` | Descriptive |
| `descriptive` | information-only | The control is reported, not rated. | `descriptive` | Descriptive |
| `not_applicable` | any | The control does not apply to the organization. | `descriptive` | Descriptive |
| `not_evaluated` | any | The setting, or another setting that decides whether the control applies, could not be read. | `descriptive` | Descriptive |
No field names the kind of control; for `failed`, a `null` `current_value` marks a manual control. More values can be added, so count a control with an unknown `status` by its `rating` and read an unknown `rating` as not Passed. The status `review` and the attestation state `review_due` are not related.
## Attestation states
`state` says whether the attestation that the response shows is in effect.
| `state` | Meaning |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `in_force` | The attestation is in effect. |
| `review_due` | The end date has come. |
| `setting_changed` | The check fails on a value other than the one whose risk was accepted, or the accepted risk was already recorded as ended. |
| `check_passing` | The check passes, so there is no risk to accept. |
When more than one reason applies, the response gives the first of `check_passing`, `setting_changed`, and `review_due`. From 00:00 UTC on its end date, an attestation is not in effect. The response has no end date, so `state` decides; an end date that was saved is the attestation activity’s [`review_date`](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#attestation-activity). Read an unknown `state` as not in effect.
## How an attestation shows in the response
The response shows some attestations and leaves others out, so a `null` `attestation` does not prove that nobody attested.
| Kind of control | Attested as | `status` | `rating` | `attestation` |
| ------------------------------------------- | -------------------------------------- | -------------------------------------------------------------------- | ---------------------- | --------------------------------------------------- |
| Manual | No attestation | `not_attested`, or `attestation_not_enabled` where nobody can attest | `not_attested` | `null` |
| Manual | Completed | `attested_completed` | `passed` | Shown |
| Manual | Accepted risk | `attested_accepted_risk` | `passed` | Shown |
| Manual | Failed (`control_failed`) | `failed` | `failed` | `null`: never shown |
| Automatic, check failed | No attestation | `failed` or `review` | `failed` | `null` |
| Automatic, check failed | Accepted risk | `failed_check_accepted_risk` | `passed` | Shown |
| Automatic, check failed | Completed | `failed`, even where the automatic check gives `review` | `failed` | `null`: never shown |
| Automatic, check failed | Failed | The `status` the automatic check gives | `failed` | `null`: never shown |
| Automatic, check passed | No attestation | `passed`, `matches_profile`, or `exceeds_baseline` | `passed` | `null` |
| Automatic, check passed | Completed | The `status` the automatic check gives | `passed` | `null`: never shown |
| Automatic, check passed | Accepted risk | The `status` the automatic check gives | `passed` | `null` while the check passes on the accepted value |
| Automatic, check passed | Failed | `failed` | `failed` | `null`: never shown |
| Information-only | Any value | `descriptive` | `descriptive` | `null`: never shown |
| Any, while the attestation is not in effect | A value that an earlier row shows | As with no attestation | As with no attestation | Shown, with a `state` other than `in_force` |
| Any, while the attestation is not in effect | A value that an earlier row leaves out | As with no attestation | As with no attestation | `null` |
Each row but the last two holds while the attestation is in effect. On an automatic control, an attestation is not in effect while the value that the check reads differs from the one that it was saved on. Every attestation that the response shows on an automatic control is an accepted risk. The [Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed) also records attestations of the kinds that the response leaves out.
## Count results
Check four things when you count controls by `rating`.
| If you count | Also check |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Passed (`passed`) | It includes every control with an accepted risk in effect, so look for `failed_check_accepted_risk` and `attested_accepted_risk`. |
| Failed (`failed`) | It includes a control attested as Failed (`control_failed`) and a failing automatic check with a Completed attestation in effect, which the Security posture page shows as Passed. |
| Descriptive (`descriptive`) | It can hide a control that could not be read, so look for `not_evaluated`. |
| Every control | A control missing from the response is not Passed and is not named, so compare `id` values with those that you have seen for the organization. |
## Who attested, and comments
`attested_by` is filled only for a key that holds `read:compliance_user_data` together with `read:compliance_org_data` or that holds `read:org_audit`. A key with only `read:compliance_user_data` gets a 403. The `user_id` in `attested_by` is the same as the `actor`’s `user_id` on the attestation activity. `attested_by` holds only the user ID: [List organization users](https://platform.claude.com/docs/en/manage-claude/compliance-org-data#list-organization-users) gives the name and email address of each current member. Before you add these scopes, see [Who can see who attested](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#who-can-see-who-attested).
The endpoint returns no comments, even when the Security posture page shows one: every `comment` is `null`, and `comments_status` is `not_enabled` or `not_permitted`. So `not_enabled` and a `null` comment do not mean the attestation has no comment. `comments_status` says how to read a `null` comment, and the schema defines these values.
| `comments_status` | Meaning |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `not_permitted` | The API key holds neither `read:compliance_user_data` nor `read:org_audit`, so every `comment` and every `attested_by` is `null`. |
| `requires_organization_key` | The API key was not created in the organization, as with a key for the parent organization, so every `comment` is `null`. Retrying does not help. |
| `available` | Comments were read, so a `null` comment means that there is none or that it was saved moments ago. |
| `not_enabled` | This endpoint does not return comments for the organization, so every `comment` is `null`. |
| `unavailable` | Comments could not be read for this response; a later request might succeed, but some causes last until the customer acts. |
More values can be added; read an unknown one as `unavailable`.
## Errors
Errors use the same body as the rest of the [Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-errors); this table lists the ones that this endpoint returns in its own way.
| Status and `error.type` | When | What to do |
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| 400 `invalid_request_error` | `anthropic-version` is missing or invalid, the Compliance API is not enabled for the parent organization, or there is a query parameter. | Fix what `error.message` names. |
| 401 `authentication_error` | The key is missing, not recognized, or not a Compliance Access Key or Admin API key. | Send a valid Compliance Access Key in `x-api-key`. |
| 403 `permission_error` | The key may not call this endpoint, usually because it lacks both `read:compliance_org_data` and `read:org_audit`. | Use a key with either scope. |
| 404 `not_found_error` | See the causes listed after this table. | Do not retry at once and never read it as no failed controls. |
| 429 `rate_limit_error` | The shared Compliance API rate limit, or this endpoint’s lower limit, is used up; `error.message` says which. | Wait for `retry-after`; see [429 Too Many Requests](https://platform.claude.com/docs/en/manage-claude/compliance-errors#429-too-many-requests). |
| 503 `overloaded_error`, with `error.details.error_code` of `posture_evaluation_failed` | The result could not be produced. | Wait for `retry-after`, then retry; if it recurs for one organization on later runs, contact Anthropic support once. |
| 503 with no `error_code`, or 504 `timeout_error` | A temporary failure. | Retry with exponential backoff. |
Causes of a 404:
* `organization_id` is not a UUID, names no organization, or names a deleted one.
* `organization_id` names the parent organization, an organization under another parent, or one that a single-organization key does not cover.
* The organization is not on Claude Enterprise, or Security posture is not available to it, as with a Claude Console organization.
* The Security posture page has been turned off for the organization (see [Security posture availability](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability)).
* Security posture is available to the organization, but the endpoint does not serve it.
* Availability could not be checked; a later request can succeed.
Every 404 has the same body, as does a path that does not exist.
## Freshness and side effects
The endpoint evaluates every control when you call it, and `evaluated_at` is that time.
* A change from the last few minutes might not show.
* A result can change with no setting changed, for example when an end date comes or Anthropic changes a recommended value.
* If Anthropic rewords a current value, an accepted risk on it is not in effect.
* A call stores no result and ends no attestation.
* Each request that passes the key, scope, and version checks without a query parameter records one `compliance_api_accessed` activity, whether it succeeds or fails; its `url` names the organization read, and `organization_uuid` is `null` for a key for the parent organization.
manage-claude/compliance-security-posture/send-events New page · 118 lines, new page
## Request the activities ## Read one activity ## If the response is empty ## Run it on a schedule ## Re-read 15 days once a day ## If you already ingest the full feed ## Check that it works ## Next steps
A whole new page. There's nothing to diff it against, so here is what it says.
---
title: Send Security posture events to your SIEM
url: https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events
description: Request the Security posture activities from the Compliance API Activity Feed, read one of them field by field, and keep your SIEM current with a scheduled read that catches late activities.
---
<Note>
To enable the Compliance API, see [Set up the Compliance API](https://platform.claude.com/docs/en/manage-claude/compliance-api-access).
</Note>
This page takes you from a Compliance Access Key to Security posture activities arriving as events in your security information and event management (SIEM) system on a schedule. The overview says [which organizations have these activities](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability). You need a Compliance Access Key that covers the organization, with the `read:compliance_activities` or `read:org_audit` scope.
## Request the activities
To read only these activities, filter the feed with `activity_types[]`. In this request, `created_at.gte` sets the earliest `created_at` to read, and `order=asc` returns the oldest activities first:
```bash cURL
curl --fail-with-body -sS -G \
"https://api.anthropic.com/v1/compliance/activities" \
-H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
-H "anthropic-version: 2026-10-21" \
--data-urlencode "activity_types[]=org_security_control_attestation_updated" \
--data-urlencode "created_at.gte=2026-10-20T00:00:00Z" \
--data-urlencode "order=asc" \
--data-urlencode "limit=5000"
```
The [API reference](https://platform.claude.com/docs/en/api/compliance/activities/list) describes each parameter.
## Read one activity
Each element of the response’s `data` array is an activity like this one.
```json
{
"id": "activity_01Hq7ZtYc4Vb2NmKx8RsPd3W",
"type": "org_security_control_attestation_updated",
"created_at": "2026-10-20T15:04:00.220114Z",
"organization_id": "org_01JuY4bkwkH1x4PodBJaWmh2",
"organization_uuid": "91012d09-e48b-438e-a489-1bebfd8fa6f9",
"actor": {
"type": "user_actor",
"email_address": "[email protected]",
"user_id": "user_01WxYzAbCdEfGhJkMnPqRsTu",
"ip_address": "192.0.2.34",
"user_agent": "Mozilla/5.0..."
},
"control": "directory_sync_enabled",
"action": "attested",
"status": "accepted_risk"
}
```
* `control` names the [security control](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#controls), one recommended setting or practice.
* `action` says what happened to the [control’s attestation](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#attestations), a person’s recorded statement about the control. Here `attested` means one was recorded for a control that had none.
* `status` is the attestation’s value. Here it is Accepted risk (`accepted_risk`): the control is not in place, and the organization accepts the risk.
* `actor` here identifies the [person who attested](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#who-can-see-who-attested), by user ID and email address.
* `created_at` here is when they attested.
The [Security posture events reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference) lists more fields and values.
## If the response is empty
An empty `data` array is valid. The feed holds only changes made since it [began recording these activities for the organization](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference#what-the-feed-does-not-record). It is empty until an attestation is made or changed.
Check that the organization [has these activities](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/overview#availability). Then have someone attest to a control. After a while, repeat the request.
## Run it on a schedule
Any of these activities can become queryable later than the Activity Feed’s usual 1-minute [indexing lag](https://platform.claude.com/docs/en/manage-claude/compliance-integration-patterns#window-polling), with a `created_at` that is already in the past. So an integration that only moves forward, from a cursor or an advancing `created_at.gte`, never sees such an activity. Re-read a fixed look-back window of 4 hours on every run and drop the activities you already stored:
```text
query = activity_types[]=org_security_control_attestation_updated
& created_at.gte={now - 4 hours}
& order=asc
& limit=5000
cursor = null
loop:
if cursor is null:
page = GET /v1/compliance/activities?{query}
else:
page = GET /v1/compliance/activities?{query}&after_id={cursor}
for activity in page.data:
if activity.id is not in stored_ids:
store(activity)
add activity.id to stored_ids
if not page.has_more: break
cursor = page.last_id
```
* **Run often:** Run the loop as often as your alerts need, for example every 5 minutes.
* **Keep the same query for the whole run:** Compute `created_at.gte`, in UTC and URL-encoded, at the start of each run. Send the same filters and `order` on every page. With `order=asc`, passing `last_id` as `after_id` returns the next page of newer activities. [Paginate results](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#paginate-results) explains `after_id` and `last_id`.
* **Deduplicate on `id`:** This step is required, because consecutive runs overlap.
* **Handle failed runs:** If a request fails after the retries in [Handle Compliance API errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors), end the run. The next run reads its whole window again. If runs fail or stop for longer than 4 hours, the next [daily re-read](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#re-read-15-days-once-a-day) reads the activities they missed.
## Re-read 15 days once a day
Once a day, run the same loop with a look-back window of 15 days in place of 4 hours. This daily re-read also reads an activity that becomes queryable up to 14 days after its `created_at`.
* Record the start time of each daily re-read that completes.
* Delete a stored `id` only if you stored it more than 16 days before the latest recorded start.
* If no start is recorded, set `created_at.gte` as far back as you need; the feed keeps activities for 6 years.
* If more than a day has passed since the latest recorded start, run the next daily re-read with `created_at.gte` set to 15 days before that start.
## If you already ingest the full feed
An integration that reads the whole Activity Feed, with no `activity_types[]` filter that leaves these activities out, already receives them. Check two things:
* **Unrecognized values:** Your handler passes through any `type` or [field value](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/events-reference) that it does not recognize. See [Understand the Activity object](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed#understand-the-activity-object).
* **Late activities:** An integration that only asks for newer activities misses one that becomes queryable late. Add the [4-hour re-read](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#run-it-on-a-schedule) and the [daily 15-day re-read](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/send-events#re-read-15-days-once-a-day) to the integration.
## Check that it works
After someone attests to a control, run the loop until it stores the new activity. Then run it again: it does not store that activity a second time.
## Next steps
To alert on the time you stored an activity, not on its `created_at`, see [Detect changes in Security posture](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/detect-changes#before-you-write-a-rule). For the Open Cybersecurity Schema Framework (OCSF), see [Map Security posture events to OCSF](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/ocsf-mapping). For current results, see [Security posture results reference](https://platform.claude.com/docs/en/manage-claude/compliance-security-posture/results-reference).