access-transparency-log changedmanage-claude/access-transparency-log
Nearest release: v2.1.307, published an hour after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+27added
Lines−27removed
From line
20
where the diff opens
First seen
28 Sep 2026
this site's first read of the page
Recorded edits4to this page, all time
The whole hunk
from line 20, old and new numbered
/
from line 20
2020
2121A transparency log is a technique for making a record tamper-evident. Entries are only ever appended. Each time the log grows, its operator signs a short statement, called a checkpoint, that commits to every entry so far through a Merkle tree hash. Anyone who keeps a checkpoint can later demand proof that the current log still contains everything that checkpoint covered, unchanged and in the same order. Removing or rewriting an entry therefore cannot go unnoticed by a verifier who kept a checkpoint that covered that entry. Certificate Transparency and the Go module checksum database are built on the same technique. [C2SP tlog-tiles](https://c2sp.org/tlog-tiles) is an open specification for serving such a log as signed checkpoints plus static, cacheable tiles of hashes and entries, so that clients can fetch the hashes and compute every proof themselves.
2222
23When Access Transparency is enabled, Anthropic maintains a transparency log for your organization. It is an append-only, cryptographically signed record of Access Transparency events (`anthropic_access` and `cmek_preserve`). Each such event recorded for your organization after the log was created is appended to it. The log follows the C2SP tlog-tiles format, so tooling built for that standard understands its checkpoints, tiles, and proofs.
23When Access Transparency is enabled, Anthropic maintains a transparency log for your organization. It is an append-only, cryptographically signed record of Access Transparency events (`anthropic_access` and `cmek_preserve`). Each such event recorded for your organization after the log was created is appended to it. The log follows the C2SP tlog-tiles format, so tooling built for that standard can parse its checkpoints, tiles, and proofs.
2424
25* **One log per organization.** Each organization's log has a fixed origin string: `axt.anthropic.com/<your organization UUID>`. The origin never changes for the life of the organization.
25* **One log for each organization.** Each organization's log has a fixed origin string: `axt.anthropic.com/<your organization UUID>`. The origin never changes for the life of the organization.
2626* **Every new event becomes a leaf.** When an Access Transparency event becomes eligible to appear on your Activity Feed, it is first appended to your log as a leaf, and only then served on the feed. A leaf is a deterministic serialization of the event's documented fields. The event on your feed carries `transparency_log_leaf_index`, its zero-based position in your log.
2727* **Checkpoints commit to the whole history.** The log is a Merkle tree. Whenever it grows, Anthropic publishes a signed checkpoint: a short text document stating the log's origin, its current size, and the root hash that commits to every leaf. Each checkpoint carries exactly one signature from the log's signing key.
2828* **Two proofs follow.** An inclusion proof shows that a specific event is present at its position under a checkpoint. A consistency proof shows that a later checkpoint is an append-only extension of an earlier one you saved, so nothing between them was removed or changed.
from line 53
5353
5454## Timing
5555
56* **Events:** Access Transparency events appear on your Activity Feed within two business days of the access. An event enters the log only once it is eligible to be served, so the log never reveals an event early. Because the log is written before the feed serves the event, an entry can briefly appear in the log before its event appears on your feed. That gap is not a discrepancy.
56* **Events:** Access Transparency events appear on your Activity Feed within 2 business days of the access. An event enters the log only once it is eligible to be served, so the log never reveals an event early. Because the log is written before the feed serves the event, an entry can briefly appear in the log before its event appears on your feed. That gap is not a discrepancy.
5757* **Checkpoints:** A new checkpoint is published whenever your log grows.
5858* **Inclusion proofs:** A proof for a newly served event is available once a checkpoint covering the event's position is published, normally very shortly after the event appears. If you request one sooner, you receive a `404` and retry after a short delay.
5959* **Verification cadence:** Run your verification at least daily. Hourly is reasonable.
from line 96
9696
9797### Errors
9898
99Errors use the standard Compliance API JSON error envelope on every endpoint, including the text and binary ones. See [Errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors) for the envelope and the shared error types.
99Errors use the standard Compliance API JSON error envelope on every endpoint, including the text and binary ones. See [Handle Compliance API errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors) for the envelope and the shared error types.
100100
101101| Status | Meaning on this surface |
102102| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
from line 118
118118```bash
119119curl --fail-with-body -sS \
120120 "https://api.anthropic.com/v1/compliance/transparency_log/checkpoint" \
121 --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
122 --header "anthropic-version: 2023-06-01"
121 -H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
122 -H "anthropic-version: 2023-06-01"
123123```
124124
125125The response is `text/plain`: a C2SP [signed note](https://c2sp.org/signed-note). The body lines are the origin, the tree size in decimal, and the base64 root hash. A blank line follows, then the signature line, which starts with an em dash (U+2014), names the origin, and ends with a base64 value. Values here are illustrative:
from line 132
132132— axt.anthropic.com/25f6429a-3293-49bf-afed-cb312911554b q83vATBFAiEAvL8m…(base64)…
133133```
134134
135* The first four bytes of the decoded signature value are the signing key's `key_hash`, which tells you which entry in the [verifier key set](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#read-the-verifier-keys) to verify with. The remaining bytes are an ASN.1 DER ECDSA P-256 signature over the SHA-256 of the note body: every byte before the blank line, including the body's trailing newline.
135* The first 4 bytes of the decoded signature value are the signing key's `key_hash`, which tells you which entry in the [verifier key set](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#read-the-verifier-keys) to verify with. The remaining bytes are an ASN.1 DER ECDSA P-256 signature over the SHA-256 of the note body: every byte before the blank line, including the body's trailing newline.
136136* A checkpoint can carry additional lines after the root hash. Ignore lines you do not understand. They are covered by the signature.
137137* Ignore a signature line whose name is not your origin or whose key hash you do not hold.
138138* Never cache a checkpoint. A stale one hides the log's current size, so newly served events look uncovered.
from line 144
144144```bash
145145curl --fail-with-body -sS \
146146 "https://api.anthropic.com/v1/compliance/transparency_log/keys" \
147 --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
148 --header "anthropic-version: 2023-06-01"
147 -H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
148 -H "anthropic-version: 2023-06-01"
149149```
150150
151151```json
from line 170
170170| `origin` | string | The origin line every checkpoint of this log carries. Informational: compare checkpoints against the origin you derive yourself, not against this field |
171171| `log_keys` | array | The key that signs new checkpoints first, then every other key the log serves, newest first. Never empty |
172172| `log_keys[].verifier_key` | string | The key as a C2SP note-verifier string, `<origin>+<key_hash>+<base64 key>`, accepted by tlog-tiles tooling that supports ECDSA note keys (for example, the Go `github.com/transparency-dev/formats` module). The base64 part decodes to the algorithm byte `0x02` followed by the DER-encoded public key |
173| `log_keys[].key_hash` | string | Eight lowercase hex digits. The 4-byte selector that matches this key to a checkpoint's signature line. It is the first four bytes of `fingerprint` and is not an identity |
173| `log_keys[].key_hash` | string | Eight lowercase hex digits. The 4-byte selector that matches this key to a checkpoint's signature line. It is the first 4 bytes of `fingerprint` and is not an identity |
174174| `log_keys[].fingerprint` | string | 64 lowercase hex digits: the SHA-256 of the DER `SubjectPublicKeyInfo` |
175175| `log_keys[].algorithm` | string | The key type, currently `ecdsa_p256_sha256`. Values may be added. Skip a key whose algorithm you do not support |
176176| `log_keys[].public_key` | string | The public key as base64 DER `SubjectPublicKeyInfo` |
177177
178The `key_hash` covers only the key bytes: it is the first four bytes of SHA-256 over the DER `SubjectPublicKeyInfo`, which is the rule the ECDSA note-verifier encoding uses. It is not the name-dependent key ID that the base signed-note format defines for Ed25519 keys, so it does not change with the origin. A valid signature by a key listed in [Published key fingerprints](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#published-key-fingerprints) proves the checkpoint came from Anthropic's transparency log service. The origin line inside the signed checkpoint is what binds it to your organization. That is why you compare that line against the origin you derive yourself.
178The `key_hash` covers only the key bytes: it is the first 4 bytes of SHA-256 over the DER `SubjectPublicKeyInfo`, which is the rule the ECDSA note-verifier encoding uses. It is not the name-dependent key ID that the base signed-note format defines for Ed25519 keys, so it does not change with the origin. A valid signature by a key listed in [Published key fingerprints](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#published-key-fingerprints) proves the checkpoint came from Anthropic's transparency log service. The origin line inside the signed checkpoint is what binds it to your organization. That is why you compare that line against the origin you derive yourself.
179179
180180Keys can rotate:
181181
from line 185
185185
186186#### Published key fingerprints
187187
188Anthropic publishes the fingerprint of every key that signs checkpoints here, outside the API. This lets you check a key you hold locally against a source the serving path cannot alter. The key you hold may come from an earlier `GET /keys` response or from tooling that pins the key.
188Anthropic publishes the fingerprint of every key that signs checkpoints here, outside the API. This lets you check a key you hold locally against a source the serving path cannot alter. The key you hold might come from an earlier `GET /keys` response or from tooling that pins the key.
189189
190190| Key hash | SHA-256 fingerprint | Algorithm | Signing since | Status |
191191| ---------- | ------------------------------------------------------------------ | ------------------- | ------------- | ------------------- |
from line 208
208208curl --fail-with-body -sS -G \
209209 "https://api.anthropic.com/v1/compliance/transparency_log/inclusion" \
210210 --data-urlencode "leaf_index=41" \
211 --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
212 --header "anthropic-version: 2023-06-01"
211 -H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
212 -H "anthropic-version: 2023-06-01"
213213```
214214
215215```json
from line 254
254254curl --fail-with-body -sS -G \
255255 "https://api.anthropic.com/v1/compliance/transparency_log/consistency" \
256256 --data-urlencode "from=1180" \
257 --header "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
258 --header "anthropic-version: 2023-06-01"
257 -H "x-api-key: $ANTHROPIC_COMPLIANCE_ACCESS_KEY" \
258 -H "anthropic-version: 2023-06-01"
259259```
260260
261261```json
from line 286
286286
287287`GET /v1/compliance/transparency_log/tile/{level}/{index}`
288288
289Returns `application/octet-stream`: concatenated 32-byte SHA-256 hashes, per tlog-tiles. Tile addressing follows tlog-tiles exactly, including the `{level}` and `{index}` path grammar, the `x001/234` index form for large trees, and the partial-tile suffix `.p/{width}`. Hash tiles are the unit from which tlog-tiles clients compute proofs themselves.
289Returns `application/octet-stream`: concatenated 32-byte SHA-256 hashes, as tlog-tiles specifies. Tile addressing follows tlog-tiles exactly, including the `{level}` and `{index}` path grammar, the `x001/234` index form for large trees, and the partial-tile suffix `.p/{width}`. Hash tiles are the unit from which tlog-tiles clients compute proofs themselves.
290290
291291* Full tiles are immutable and are served with `Cache-Control: private, max-age=604800, immutable`.
292292* Partial tiles are superseded as the tree grows and are served with `Cache-Control: private, no-store`. Once a tile fills, a request for its earlier partial form can return `404` even though the full tile exists. Falling back from the partial tile to the full tile is the client's job, as tlog-tiles specifies, and standard clients already do it.
from line 296
296296
297297`GET /v1/compliance/transparency_log/tile/entries/{index}`
298298
299Returns `application/octet-stream`: consecutive leaf entries, each prefixed with its big-endian `uint16` length, per tlog-tiles. Entry bundles contain event plaintext: the [canonical bytes](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#how-an-event-becomes-a-leaf) of each Access Transparency event. That is why the whole surface requires the Activity Feed's scope. Addressing, the partial form, caching, and errors are identical to hash tiles.
299Returns `application/octet-stream`: consecutive leaf entries, each prefixed with its big-endian `uint16` length, as tlog-tiles specifies. Entry bundles contain event plaintext: the [canonical bytes](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#how-an-event-becomes-a-leaf) of each Access Transparency event. That is why the whole surface requires the Activity Feed's scope. Addressing, the partial form, caching, and errors are identical to hash tiles.
300300
301301## The `transparency_log_leaf_index` field on Activity Feed events
302302
from line 303
303303`anthropic_access` and `cmek_preserve` events on `GET /v1/compliance/activities` carry `transparency_log_leaf_index`, an integer, whenever the event has a leaf. Other activity types never carry it.
304304
305305* **The key is absent, not `null`, when the event has no leaf.** A robust verifier treats an absent key and a `null` value the same way.
306* **An event is served without `transparency_log_leaf_index` in only two cases.** The first is while your organization is not enrolled in Access Transparency, that is, before enrollment or between an un-enrollment and a re-enrollment. The second is when the event was recorded before your organization's log was created. For an organization enrolled before the transparency log was introduced, that includes its earlier history. Once your log exists and while you are enrolled, every event is appended to the log before the feed serves it. If a fault prevents the feed from learning the index, the feed delays the event rather than serving it without one. The event is not lost: it is already in the log and appears on the feed, index included, once the fault is remediated. An index-less event is not expected when it is dated after your log was created and falls inside a period when you were enrolled.
306* **An event is served without `transparency_log_leaf_index` in only two cases.** The first is while your organization is not enrolled in Access Transparency, that is, before enrollment or between an un-enrollment and a re-enrollment. The second is when the event was recorded before your organization's log was created. For an organization enrolled before the transparency log was introduced, that includes its earlier history. Once your log exists and while you are enrolled, every event is appended to the log before the feed serves it. If a fault prevents the feed from obtaining the index, the feed delays the event rather than serving it without one. The event is not lost: it is already in the log and appears on the feed, index included, once the fault is remediated. An index-less event is not expected when it is dated after your log was created and falls inside a period when you were enrolled.
307307* **A present index is a pointer, not a proof.** Verify inclusion before treating the event as committed in the log. The anomaly worth escalating is a present index whose inclusion proof still cannot be fetched long after a covering checkpoint should have been published.
308308* The index is assigned when the event is appended to the log and is not one of the fields that make up the leaf.
309309
from line 393
393393
394394Each `run` fetches the latest checkpoint and verifies its signature and origin line. It then proves the log is an append-only extension of the checkpoint the previous run saved. Next it pages through the Access Transparency events on your Activity Feed. It starts seven days (by `created_at`) before the newest event the previous run read, so that events listed late or out of order are still picked up. It rebuilds each event's leaf, verifies an inclusion proof for it, and compares any event it verified before against what it recorded then. Finally, it saves the new checkpoint and its progress to the `--state` file, which the next run starts from. Run it at least daily. Hourly is reasonable. With a parent-organization key, run one copy per child organization, each with its own `--org` and `--state` file. Each child organization's UUID also comes from the Claude Console, not from the Compliance API responses you are verifying. To find it, switch to the child organization in the account menu at the bottom of the Console sidebar, then open the [Organization](https://platform.claude.com/settings/organization) page (`platform.claude.com/settings/organization`). You can also find it in your parent organization's list of organizations in the Console. `axt-verify checkpoint` does only the checkpoint and append-only steps. `axt-verify events FILE` verifies events you already hold, such as an auditor's sample or your own export. It proves that each event in the file is still committed in the log under the current checkpoint. It does not read the feed or touch the state file.
395395
396One limit follows from that window: `run` re-reads only the last seven days of events, so it re-checks recently served events (step 7), not your whole history. Keep the events you export (see [Keep your own checkpoint archive](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#keep-your-own-checkpoint-archive)). `axt-verify events FILE` proves at any later date that those copies are still committed in the log, but it does not re-read the feed. To detect an older event removed from or rewritten on the feed, re-export that range from the Activity Feed and compare it with the copies you kept. You can also verify the re-export itself with `axt-verify events FILE`. The seven-day overlap is longer than the feed's two-business-day delivery time, so a late-arriving event still falls inside a later run's window. `--overlap` changes the duration if you need to.
396One limit follows from that window: `run` re-reads only the last 7 days of events, so it re-checks recently served events (step 7), not your whole history. Keep the events you export (see [Keep your own checkpoint archive](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#keep-your-own-checkpoint-archive)). `axt-verify events FILE` proves at any later date that those copies are still committed in the log, but it does not re-read the feed. To detect an older event removed from or rewritten on the feed, re-export that range from the Activity Feed and compare it with the copies you kept. You can also verify the re-export itself with `axt-verify events FILE`. The 7-day overlap is longer than the feed's 2-business-day delivery time, so a late-arriving event still falls inside a later run's window. `--overlap` changes the duration if you need to.
397397
398398If you need your own implementation instead, follow the preceding checklist with a tlog-tiles library that supports ECDSA note keys.
399399
400400### Interpret the result
401401
402`axt-verify` prints your origin, the tree size and root hash of the checkpoint it verified, the tree size the append-only check started from, and a count of events by outcome. Pass `--json` to get the same report as one JSON object per line. Each event has one of four outcomes:
402`axt-verify` prints your origin, the tree size and root hash of the checkpoint it verified, the tree size the append-only check started from, and a count of events by outcome. Pass `--json` to get the same report as one JSON object on each line. Each event has one of four outcomes:
403403
404404* **Verified:** the leaf rebuilt from the served event is committed at the event's index in the signed log.
405405* **Pending:** the event's index is beyond the latest published checkpoint. This is normal for a short time after an event appears. In `run`, `axt-verify` remembers the event, verifies it on a later run once a checkpoint covers it, and fails it if that takes longer than 24 hours. `events FILE` has no later run to settle it, so it waits up to a minute for a covering checkpoint to be published. If none arrives, it reports the event as not yet covered and ends with exit status `3`. Run it again later. If `events FILE` reports the same event as not yet covered on two runs at least a day apart, treat it as a verification failure and escalate as for exit status `1`.
from line 406
406406* **Not logged:** the event was served without an index. An event is served without `transparency_log_leaf_index` only while your organization is not enrolled in Access Transparency, or when it was recorded before your organization's log was created (see [The `transparency_log_leaf_index` field on Activity Feed events](https://platform.claude.com/docs/en/manage-claude/access-transparency-log#the-transparency-log-leaf-index-field-on-activity-feed-events)). `axt-verify` reports such events as not logged and does not fail the run on them. An index-less event is not expected when it is dated after your log was created and falls inside a period when you were enrolled. Review the not-logged list in the run's summary or `--json` output rather than relying on the exit status alone.
407407* **Failed:** see exit status `1`.
408408
409The exit status tells your scheduler what happened:
409The exit status tells your scheduler what occurred:
410410
411411* **`0`:** Nothing failed. Not-logged events are reported, not failed, and so are pending events in `run`.
412412
from line 422
422422 * An event still pending 24 hours after the run first saw it.
423423 * A refused inclusion proof (`400`, `401`, or `403`) for an event the feed served you.
424424 * An inclusion proof returned for a different `leaf_index` from the one requested.
425 * In `events FILE`, an event at an index the latest checkpoint already covered when the check began, for which no inclusion proof is served before the wait runs out.
425 * In `events FILE`, an event at an index the latest checkpoint already covered when the check started, for which no inclusion proof is served before the wait runs out.
426426 * An event whose `organization_uuid` is not the organization UUID you passed with `--org`. When a parent organization runs `events FILE` on an export that covers several child organizations, every other organization's event fails this way, so split the export by organization first and verify each part with its own `--org`.
427427 * The same activity `id` at two different indices, or twice at one index with different content, within one run or one `events FILE` input.
428428 * An event whose leaf cannot be rebuilt: for example, a documented field that is not a string, a field name that appears twice, or a `type` that is missing or is an unrecognized variant of an Access Transparency type. `events FILE` skips rows of other activity types and does not fail them.
from line 441
441441 * An unexpected response.
442442 * A state or `--save` file that could not be written.
443443
444 An exit status `3` with `404` responses is expected until Anthropic has recorded a first Access Transparency event for your organization, because every transparency log endpoint returns `404` until that event creates the log. Escalate if the transparency log endpoints still return `404` more than a few days after your Activity Feed first shows an Access Transparency event, whether or not that event carries a `transparency_log_leaf_index`. That combination is not expected. Once a run has succeeded, escalate an exit status `3` that persists.
444 An exit status `3` with `404` responses is expected until Anthropic has recorded a first Access Transparency event for your organization, because every transparency log endpoint returns `404` until that event creates the log. Escalate if the transparency log endpoints still return `404` more than a few days after your Activity Feed first shows an Access Transparency event, regardless of whether that event carries a `transparency_log_leaf_index`. That combination is not expected. Once a run has succeeded, escalate an exit status `3` that persists.
445445
446446### Keep your own checkpoint archive
447447
from line 471
471471 </Accordion>
472472
473473 <Accordion title="Can I verify all of my child organizations with one key?">
474 Yes. A parent-organization key reads any enrolled child organization's log by passing `organization_id`. Each child organization has its own log, origin, and saved checkpoint. Run one verification per child organization, each with its own state.
474 Yes. A parent-organization key reads any enrolled child organization's log by passing `organization_id`. Each child organization has its own log, origin, and saved checkpoint. Run a separate verification, with its own state, for each child organization.
475475 </Accordion>
476476</AccordionGroup>
477477
from line 480
480480* [Access Transparency](https://platform.claude.com/docs/en/manage-claude/access-transparency)
481481* [Query the Activity Feed](https://platform.claude.com/docs/en/manage-claude/compliance-activity-feed)
482482* [Compliance API overview](https://platform.claude.com/docs/en/manage-claude/compliance-api)
483* [Errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors)
483* [Handle Compliance API errors](https://platform.claude.com/docs/en/manage-claude/compliance-errors)
484484* [axt-verify](https://github.com/anthropics/axt-verify), Anthropic's open-source verifier for the transparency log
485485* [C2SP tlog-tiles](https://c2sp.org/tlog-tiles) and [C2SP signed note](https://c2sp.org/signed-note), the wire formats for tiles, entry bundles, and checkpoints
486486* [RFC 9162](https://www.rfc-editor.org/rfc/rfc9162), the Merkle tree, inclusion proof, and consistency proof algorithms
No line in this hunk matches that.