Agent Receipt Schema
An Agent Receipt is a W3C Verifiable Credential with type AgentReceipt. This page documents the full schema with all required and optional fields.
Full receipt example
Section titled “Full receipt example”{ "@context": [ "https://www.w3.org/ns/credentials/v2", "https://agentreceipts.ai/context/v2" ], "id": "urn:receipt:550e8400-e29b-41d4-a716-446655440000", "type": ["VerifiableCredential", "AgentReceipt"], "version": "0.5.0",
"issuer": { "id": "did:agent:claude-cowork-instance-abc123", "type": "AIAgent", "name": "Claude Cowork", "operator": { "id": "did:org:anthropic", "name": "Anthropic" }, "model": "claude-sonnet-4-6", "session_id": "session_xyz789", "runtime": { "agent_id": "a3e49db54342a92d4", "agent_type": "general-purpose" } },
"issuanceDate": "2026-03-31T14:30:00Z",
"credentialSubject": { "principal": { "id": "did:user:otto-abc", "type": "HumanPrincipal" },
"action": { "id": "act_7f3a1b2c-d4e5-46f7-a8b9-c0d1e2f3a4b5", "type": "filesystem.file.delete", "risk_level": "high", "target": { "system": "local", "resource": "/tmp/old-report.pdf" }, "parameters_hash": "sha256:a3f1c2d4e5b6a7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1d6", "parameters_disclosure": { "path": "/tmp/old-report.pdf" }, "peer_credential": { "platform": "darwin", "pid": 8421, "uid": 501, "gid": 20, "exe_path": "/Applications/Claude.app/Contents/MacOS/Claude" }, "timestamp": "2026-03-31T14:30:00Z" },
"intent": { "conversation_hash": "sha256:b4e2d1f3a5c6b7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1e7", "prompt_preview": "Clean up old reports in /tmp", "prompt_preview_truncated": true, "reasoning_hash": "sha256:c5f3e2d4a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2f8" },
"outcome": { "status": "success", "reversible": false, "state_change": { "before_hash": "sha256:d604f3e5a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3a9", "after_hash": "sha256:e7a504f6a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4ba" } },
"authorization": { "scopes": ["filesystem:write"], "granted_at": "2026-03-31T14:00:00Z", "expires_at": "2026-03-31T15:00:00Z" },
"chain": { "sequence": 1, "previous_receipt_hash": null, "chain_id": "chain_session_xyz789" } },
"proof": { "type": "Ed25519Signature2020", "created": "2026-03-31T14:30:01Z", "verificationMethod": "did:agent:claude-cowork-instance-abc123#key-1", "proofPurpose": "assertionMethod", "proofValue": "u..." }}Top-level fields
Section titled “Top-level fields”| Field | Required | Description |
|---|---|---|
@context | Yes | JSON-LD context. Must include the W3C VC v2 and Agent Receipt context URIs in order. |
id | Yes | Globally unique identifier. Must be urn:receipt:<uuid>. |
type | Yes | Must be ["VerifiableCredential", "AgentReceipt"]. |
version | Yes | Protocol version. Must be "0.1.0", "0.2.0", "0.2.1", "0.3.0", "0.4.0", or "0.5.0". Verifiers MUST accept all six. Versions 0.1.0–0.4.0 reference Agent Receipts context v1; 0.5.0 references v2. |
issuer | Yes | The agent or platform that issued the receipt. |
issuanceDate | Yes | ISO 8601 datetime when the receipt was issued. May differ from action.timestamp. |
credentialSubject | Yes | The receipt payload. |
proof | Yes | Cryptographic proof. |
Issuer
Section titled “Issuer”| Field | Required | Description |
|---|---|---|
id | Yes | DID or URI identifying the agent instance. |
type | No | Should be "AIAgent". |
name | No | Human-readable agent name. |
operator.id | Conditional | DID or URI of the operating entity. Required when operator is present. |
operator.name | Conditional | Human-readable operator name. Required when operator is present. |
model | No | Model identifier (e.g. claude-sonnet-4-6). |
session_id | No | Opaque session identifier. |
runtime | No | Open container for runtime/observability metadata (added in v0.5.0, ADR-0026). Absent for the root agent. Unlike the other issuer fields it is extensible: it carries the members below plus any additional keys a runtime supplies, typed @json in the context so JSON-LD treats it as an opaque literal. |
runtime.agent_id | No | Identifier of the sub-agent that issued the receipt. |
runtime.agent_type | No | Runtime-reported agent type label (e.g. general-purpose). |
Credential subject
Section titled “Credential subject”principal
Section titled “principal”| Field | Required | Description |
|---|---|---|
id | Yes | DID or URI identifying the human or org. |
type | No | "HumanPrincipal" or "OrganizationPrincipal". |
action
Section titled “action”| Field | Required | Description |
|---|---|---|
id | Yes | Unique action ID. Format: act_<uuid>. |
type | Yes | Action type from the taxonomy. |
risk_level | Yes | low, medium, high, or critical. |
target.system | No | The system or service acted upon. |
target.resource | No | The specific resource within the system. |
parameters_hash | No | sha256: prefixed hash of action parameters (RFC 8785 canonical JSON). Always authoritative for parameter integrity; parameters_disclosure is additive metadata. |
parameters_disclosure | No | Operator-controlled disclosure of action parameters. Either the legacy flat-map (v0.2.x — { [key: string]: string }) or the HPKE asymmetric encryption envelope defined by ADR-0012 (v0.3.0+). Mode is per-emitter; a receipt MUST NOT mix shapes. See parameters_disclosure envelope (HPKE) for the envelope shape and an example. Operators MUST NOT place plaintext secrets or PII in the legacy flat-map form. |
peer_credential | No | OS-attested peer process metadata captured by the daemon at the SDK↔daemon boundary (platform, pid, optional uid/gid/exe_path). Present only on receipts emitted through a daemon (ADR-0010); absent on direct SDK emissions. Daemon-attested, not agent-claimed. |
emitter_metadata | No | Daemon-observed emitter-side metadata. Currently a single drop_count field on synthetic events_dropped receipts (ADR-0010). Daemon-attested, not agent-claimed. |
timestamp | Yes | ISO 8601 datetime when the action was executed. |
trusted_timestamp | No | Base64-encoded RFC 3161 TimeStampToken. Absent (not null) when not present — see Optional-field rule. |
idempotency_key | No | Stable identifier for the logical operation this action represents (e.g. a request ID). When an agent retries a tool call, the SDK or MCP proxy stamps the same idempotency_key on every receipt for that operation; verifiers surface duplicates across a chain as a warning, not a failure (retries are legitimate). Non-empty string when present; absent (not null) otherwise. Added in v0.4.0 (ADR-0019 §S5). |
parameters_disclosure envelope (HPKE)
Section titled “parameters_disclosure envelope (HPKE)”parameters_hash is always authoritative for parameter integrity. parameters_disclosure is optional, additive metadata that lets an operator make the underlying parameters recoverable. It takes one of two shapes — mode is per-emitter, and a single receipt MUST NOT mix them:
- Legacy flat-map (v0.2.x) —
{ [key: string]: string }of operator-redacted plaintext, as shown in the full receipt example above. Operators MUST NOT place plaintext secrets or PII here. - HPKE envelope (v0.3.0+, ADR-0012) — the parameters are encrypted to a forensic recipient so they never appear in plaintext on the wire. This is the headline v0.3.0 disclosure mode.
The v1 envelope is HPKE base mode (RFC 9180) with ciphersuite KEM = DHKEM(X25519, HKDF-SHA256), KDF = HKDF-SHA256, AEAD = AES-256-GCM. Both the HPKE info and AEAD aad are the empty string; there is no nonce field (HPKE single-shot derives it internally). The plaintext is the RFC 8785 canonical JSON of the parameters object — top-level strings, numbers, and arrays are not valid plaintext; wrap them in an object.
| Field | Required | Description |
|---|---|---|
v | Yes | Envelope schema version. The JSON string "1" (not the number 1). Any change to the field set, encoding, or ciphersuite is a future "2". |
alg | Yes | Ciphersuite tag. Exactly "hpke-x25519-hkdf-sha256-aes-256-gcm" — no whitespace or case variation. |
recipients | Yes | Array of recipient descriptors. Exactly one entry in v1 (multi-recipient is reserved for a future envelope version). |
recipients[].kid | Yes | Recipient public-key identifier — either an ADR-0007 did:key URL with an encryption-key fragment (e.g. did:key:z6Mk…#enc-1) or a sha256:<hex> fingerprint. An index only; not itself authenticated. |
recipients[].enc | Yes | HPKE encapsulated key (RFC 9180 §4.1) — the 32-byte X25519 ephemeral public key as 43 unpadded base64url characters. |
ct | Yes | AEAD ciphertext including the 16-byte GCM tag, as unpadded base64url (no =, +, or /). |
"parameters_disclosure": { "v": "1", "alg": "hpke-x25519-hkdf-sha256-aes-256-gcm", "recipients": [ { "kid": "did:key:z6LSeu9HkTHSfLLeUs2nnzUSNedgDUevfNQUQUaHL9XJ7Z5W#enc-1", "enc": "N_2jVnvb1ijohmjDyNfpfR0SU7bU6m1EwVD3QfG_RDE" } ], "ct": "YGn3i4NpiZxHjeZVggTP8lTxb0ZVdLl-2HjW31qsvo28PjQ_Lt_UQgAMidEXjzwhJPHM7OM"}This envelope decrypts to {"command":"echo \"build complete\""} for the holder of the recipient key. It is byte-for-byte the first conformance vector in spec/test-vectors/disclosure-envelope/vectors.json, which all three SDKs reproduce. The envelope shape is validated by the sibling parameters-disclosure.schema.json (also inlined as $defs/parametersDisclosureEnvelope in the main schema so single-file validators resolve it without external refs).
intent
Section titled “intent”| Field | Required | Description |
|---|---|---|
conversation_hash | No | sha256: hash of the conversation context. |
prompt_preview | No | Plain-text preview of the triggering prompt (may be truncated). |
prompt_preview_truncated | No | true if preview was truncated. |
reasoning_hash | No | sha256: hash of the agent’s reasoning trace. |
outcome
Section titled “outcome”| Field | Required | Description |
|---|---|---|
status | Yes | success, failure, or pending. |
error | No | Error message when status is failure. Absent (not null) otherwise — see Optional-field rule. |
reversible | No | true if the action can be undone. |
reversal_method | No | Machine-readable reversal method (e.g. gmail:undo_send). Absent (not null) when not applicable. |
reversal_window_seconds | No | Seconds within which reversal is possible. Absent (not null) when not applicable. |
reversal_of | No | urn:receipt:<uuid> of the original receipt this receipt reverses. Present only on reversal receipts. |
response_hash | No | sha256: prefixed hash of the tool’s response (RFC 8785 canonical JSON). |
state_change.before_hash | Conditional | sha256: hash of state before. Required when state_change is present. |
state_change.after_hash | Conditional | sha256: hash of state after. Required when state_change is present. |
authorization
Section titled “authorization”| Field | Required | Description |
|---|---|---|
scopes | Conditional | Authorization scopes. Required when authorization is present. |
granted_at | Conditional | When authorization was granted. Required when authorization is present. |
expires_at | No | When authorization expires. |
grant_ref | No | Reference to authorization grant (e.g. Grantex token). Absent (not null) when not applicable — see Optional-field rule. |
delegation
Section titled “delegation”Present when this chain was spawned by delegation from another agent. All fields are required when delegation is present.
| Field | Required | Description |
|---|---|---|
parent_chain_id | Conditional | chain_id of the delegating agent’s chain. Required when delegation is present. |
parent_receipt_id | Conditional | id of the receipt in the parent chain where delegation occurred. Required when delegation is present. |
delegator.id | Conditional | DID or URI of the delegating agent (the parent chain’s issuer). Required when delegation is present. |
| Field | Required | Description |
|---|---|---|
chain_id | Yes | Opaque identifier grouping receipts into a chain. |
sequence | Yes | Monotonically increasing integer, starting at 1. |
previous_receipt_hash | Yes | sha256: hash of previous receipt, or null for first in chain. |
terminal | No | true if this is the final receipt in the chain. Enables tail-truncation detection by verifiers — see Receipt Chain Verification. Explicit false is schema-invalid; omit the field instead. |
status | No | Only meaningful alongside terminal: true. One of "complete" (issuer reached normal end-of-session) or "interrupted" (best-effort terminator emitted on signal or known abort path). Absent on a terminal receipt is equivalent to "complete". A non-terminal receipt carrying status is schema-invalid. The verifier-derived value "unknown" (chains with no terminal) is never written on the wire. |
| Field | Required | Description |
|---|---|---|
type | Yes | Must be "Ed25519Signature2020". |
created | Yes | ISO 8601 datetime when the proof was created. |
verificationMethod | Yes | DID URL of the signing key. The did:agent: method used in examples is an illustrative placeholder — DID resolution is not specified in the current protocol (see ADR-0007). |
proofPurpose | Yes | Must be "assertionMethod". |
proofValue | Yes | Multibase-encoded (u-prefixed base64url, no padding) Ed25519 signature. |
Optional-field rule
Section titled “Optional-field rule”Spec §7.1.1 (tightened in v0.2.1) draws a hard line between required-nullable and optional fields:
- Required-nullable fields MUST be emitted with their value, including the explicit JSON
nullliteral when the value is null. The only such field ischain.previous_receipt_hash—nullfor the first receipt in a chain, a hash string for all subsequent receipts. - Optional fields MUST NOT be emitted when their value is null or absent.
"error": null,"trusted_timestamp": null,"grant_ref": null,"reversal_method": null, and"reversal_window_seconds": nullare all schema-invalid — omit the field entirely instead. An SDK that receivesnullon an optional field MUST normalise it to absent before canonicalising.
This rule keeps all three SDKs producing byte-identical RFC 8785 canonical output for the same logical receipt, regardless of whether an optional field was set to null or omitted by the caller.
JSON Schema
Section titled “JSON Schema”A machine-readable JSON Schema (draft 2020-12) is available at spec/schema/agent-receipt.schema.json. The envelope shape of parameters_disclosure (v0.3.0+) is also published as a sibling schema for standalone validation: spec/schema/parameters-disclosure.schema.json.