Receipt Format Reference
Every tool invocation, whether allowed or denied, produces a signed receipt. Receipts are the immutable audit trail of the chio protocol. This page documents the complete receipt structure, signing process, and verification procedure.
ChioReceipt
The ChioReceipt is the top-level signed structure. Every field is present in the canonical JSON serialization.
| Field | Type | Description |
|---|---|---|
id | string | Unique receipt ID. UUIDv7 (timestamp-prefixed) for temporal ordering |
timestamp | u64 | Unix timestamp (seconds) when the receipt was created |
capability_id | string | ID of the capability token that was exercised or presented |
tool_server | string | Tool server that handled the invocation |
tool_name | string | Tool that was invoked or attempted |
action | ToolCallAction | The tool call action that was evaluated (parameters + hash) |
decision | Decision | The kernel's verdict on this tool call |
content_hash | string | SHA-256 hash of the evaluated content |
policy_hash | string | SHA-256 hash of the policy that was applied |
evidence | GuardEvidence[] | Per-guard evidence collected during evaluation (omitted when empty) |
metadata | JSON (optional) | Optional receipt metadata for financial, governed-transaction, or runtime-assurance details |
trust_level | TrustLevel | Strength of kernel mediation that produced this receipt. Defaults to Mediated; older receipts omitting this field deserialize to Mediated for backward compatibility |
tenant_id | string (optional) | Tenant identifier for multi-tenant deployments, derived from the authenticated session (never from caller-provided fields). Omitted from the wire when unset. Part of the signed body, so verifiers computing canonical bytes without this field will fail on multi-tenant deployments |
kernel_key | PublicKey (hex) | The kernel's Ed25519 public key (for verification without out-of-band lookup) |
algorithm | SigningAlgorithm (optional) | Signing algorithm used for signature. Absent means Ed25519 (backward compatibility). Informational only: verification dispatches off the self-describing signature encoding |
signature | Signature (hex) | Ed25519 signature over canonical JSON of all fields above |
Receipt body vs. signed receipt
signature. The body is serialized to canonical JSON (RFC 8785), and those bytes are signed directly with the kernel's Ed25519 private key to produce the signature field. Ed25519 hashes internally as part of EdDSA; there is no separate SHA-256 pre-hash.Decision
The Decision enum represents the kernel's verdict. It is serialized as a tagged union with a verdict discriminator field.
| Variant | Payload | Description |
|---|---|---|
allow | none | The tool call was allowed and executed |
deny | reason (string), guard (string) | The tool call was denied. Includes the human-readable reason and the guard that triggered the denial |
cancelled | reason (string) | The tool call was interrupted by explicit cancellation |
incomplete | reason (string) | The tool call did not reach a complete terminal result |
JSON Serialization
{
"verdict": "allow"
}{
"verdict": "deny",
"reason": "path matches forbidden pattern **/.env",
"guard": "forbidden-path"
}{
"verdict": "cancelled",
"reason": "user cancelled the operation"
}{
"verdict": "incomplete",
"reason": "tool server did not respond within timeout"
}ToolCallAction
Describes the tool call that was evaluated. Contains the raw parameters and their canonical hash for integrity verification.
| Field | Type | Description |
|---|---|---|
parameters | JSON value | The parameters that were passed to the tool (or attempted) |
parameter_hash | string | SHA-256 hash of the canonical JSON of parameters |
The parameter_hash is computed by serializing parameters to canonical JSON (RFC 8785), then computing the SHA-256 hex digest. This allows verifiers to confirm that parameters were not modified after receipt creation.
{
"parameters": {
"path": "./workspace/README.md"
},
"parameter_hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
}GuardEvidence
Evidence from a single guard's evaluation. The evidence array contains one entry per guard that was evaluated.
| Field | Type | Description |
|---|---|---|
guard_name | string | Name of the guard (e.g. forbidden-path) |
verdict | bool | true if the guard passed, false if it denied |
details | string (optional) | Optional details about the guard's decision |
[
{ "guard_name": "forbidden-path", "verdict": true },
{ "guard_name": "path-allowlist", "verdict": true },
{ "guard_name": "shell-command", "verdict": true },
{ "guard_name": "egress-allowlist", "verdict": true },
{ "guard_name": "mcp-tool", "verdict": true },
{ "guard_name": "secret-leak", "verdict": true },
{ "guard_name": "patch-integrity", "verdict": true },
{
"guard_name": "forbidden-path",
"verdict": false,
"details": "path matches forbidden pattern **/.env"
}
]Financial Metadata
For tool calls governed by monetary grants, the metadata field includes a financial key with detailed cost and budget information.
| Field | Type | Description |
|---|---|---|
grant_index | u32 | Index of the matching grant in the capability token's scope |
cost_charged | u64 | Cost charged in currency minor units (e.g. cents for USD) |
currency | string | ISO 4217 currency code (e.g. USD) |
budget_remaining | u64 | Remaining budget after this charge, in minor units |
budget_total | u64 | Total budget for this grant, in minor units |
delegation_depth | u32 | Depth of the delegation chain at invocation time |
root_budget_holder | string | Identifier of the root budget holder in the delegation chain |
payment_reference | string (optional) | Payment reference for external settlement systems |
settlement_status | SettlementStatus | NotApplicable, Pending, Settled, or Failed |
cost_breakdown | JSON (optional) | Optional itemized cost decomposition reported by the tool (e.g. input tokens, output tokens, fixed fee) |
oracle_evidence | OracleConversionEvidence (optional) | Rate evidence for cross-currency conversions |
attempted_cost | u64 (optional) | Cost that was attempted but denied (populated on denials that pre-charged) |
OracleConversionEvidence
Evidence for FX conversions when cost_charged is settled in a currency different from the grant currency.
| Field | Type | Description |
|---|---|---|
from_currency | string | ISO 4217 source currency |
to_currency | string | ISO 4217 target currency |
rate_numerator | u64 | Rate numerator (target units per source unit) |
rate_denominator | u64 | Rate denominator |
margin_bps | u32 | Applied margin in basis points |
oracle_source | string | Identifier of the rate oracle |
rate_timestamp | u64 | Unix seconds when the rate was observed |
Signing Process
The receipt signing process is deterministic and reproducible. Any party with the receipt body can verify the signature.
- Construct the receipt body. All fields except
signature. - Serialize to canonical JSON. Use RFC 8785 JSON Canonicalization Scheme (JCS): keys sorted lexicographically, no whitespace, deterministic number formatting.
- Sign with Ed25519. Sign the canonical JSON bytes directly with the kernel's Ed25519 private key. Ed25519 hashes internally as part of EdDSA; there is no separate SHA-256 pre-hash.
- Attach signature. Embed the hex-encoded signature and the kernel's public key in the receipt.
Canonical JSON is required
Verification
Receipt verification can be performed by any party with no additional context. The receipt is self-contained.
- Extract the body. Take every field except
signature. - Re-serialize to canonical JSON. Apply the same RFC 8785 process used during signing.
- Verify Ed25519 signature. Verify the
signatureagainst the canonical JSON bytes directly using thekernel_key. Ed25519-verify operates on the bytes, not on a separate SHA-256 pre-hash. - Verify parameter hash. Recompute the SHA-256 over RFC 8785 canonical JSON of
action.parametersand compare withaction.parameter_hash.
import {
verifyReceipt,
parseReceiptJson,
} from "@chio-protocol/sdk/invariants";
// Parse the receipt from JSON
const receipt = parseReceiptJson(receiptJsonString);
// Verify signature and parameter hash
const result = await verifyReceipt(receipt);
if (result.signatureValid && result.parameterHashValid) {
console.log("Receipt is valid");
} else {
console.error("Receipt verification failed", result);
}# Verify using openssl (manual)
# 1. Extract body (all fields except "signature")
# 2. Serialize to canonical JSON
# 3. Verify Ed25519 signature against kernel_key
# Or use the SDK:
$ node -e "
const { verifyReceiptJson } = require('@chio-protocol/sdk/invariants');
const fs = require('fs');
const receipt = fs.readFileSync('receipt.json', 'utf8');
verifyReceiptJson(receipt).then(r => console.log(r));
"Complete JSON Example
{
"id": "019076a3-4b5c-7d8e-9f01-234567890abc",
"timestamp": 1744537862,
"capability_id": "cap_7f3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7de91d",
"tool_server": "srv-files",
"tool_name": "read_file",
"action": {
"parameters": {
"path": "./workspace/README.md"
},
"parameter_hash": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
},
"decision": {
"verdict": "allow"
},
"content_hash": "d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8",
"policy_hash": "b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6",
"evidence": [
{ "guard_name": "forbidden-path", "verdict": true },
{ "guard_name": "path-allowlist", "verdict": true },
{ "guard_name": "shell-command", "verdict": true },
{ "guard_name": "egress-allowlist", "verdict": true },
{ "guard_name": "mcp-tool", "verdict": true },
{ "guard_name": "secret-leak", "verdict": true },
{ "guard_name": "patch-integrity", "verdict": true }
],
"metadata": {
"financial": {
"grant_index": 0,
"cost_charged": 1,
"currency": "USD",
"budget_remaining": 999,
"budget_total": 1000,
"delegation_depth": 0,
"root_budget_holder": "ca-prod-01",
"settlement_status": "Settled",
"cost_breakdown": {
"base": 1
}
}
},
"kernel_key": "9c7b3f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e",
"signature": "e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6"
}Deny Receipt Example
{
"id": "019076a3-5c6d-7e8f-0a12-345678901bcd",
"timestamp": 1744537863,
"capability_id": "cap_7f3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7de91d",
"tool_server": "srv-files",
"tool_name": "read_file",
"action": {
"parameters": {
"path": "./workspace/.env"
},
"parameter_hash": "f0e1d2c3b4a5968778695a4b3c2d1e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d"
},
"decision": {
"verdict": "deny",
"reason": "path matches forbidden pattern **/.env",
"guard": "forbidden-path"
},
"content_hash": "c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5",
"policy_hash": "b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6",
"evidence": [
{
"guard_name": "forbidden-path",
"verdict": false,
"details": "path matches forbidden pattern **/.env"
}
],
"kernel_key": "9c7b3f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e",
"signature": "d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6"
}Receipt Querying
Receipts can be queried from the receipt store using filters. The CLI and SDK both support the same filter set:
| Filter | Type | Description |
|---|---|---|
capability | string | Filter by capability ID |
tool_server | string | Filter by tool server ID |
tool_name | string | Filter by tool name |
outcome | string | Filter by decision: allow, deny, cancelled, incomplete |
since | u64 (Unix seconds) | Receipts with timestamp >= value |
until | u64 (Unix seconds) | Receipts with timestamp <= value |
min_cost | u64 | Minimum cost in minor units (financial receipts) |
max_cost | u64 | Maximum cost in minor units (financial receipts) |
limit | integer | Maximum results per page (default 50) |
cursor | u64 | Pagination cursor (seq value to start after) |
# All denials in the last hour
$ chio receipt list --outcome deny --since $(date -v-1H +%s)
# Financial receipts over $1.00
$ chio receipt list --min-cost 100
# Receipts for a specific capability
$ chio receipt list --capability cap_7f3a...e91d --limit 100Storage and Merkle-Committed Log
The local receipt store durably persists every signed receipt along with its sequence number. Beyond durable storage, receipts are periodically batched into checkpoints: each checkpoint commits to a Merkle root over the receipts it contains, letting verifiers check inclusion of any single receipt with an O(log n) proof instead of replaying the entire log.
- Checkpoint. A signed commitment over a Merkle root of a contiguous window of receipts, plus the window's first and last sequence numbers and timestamp.
- Inclusion proof. For a given receipt, the set of sibling hashes needed to reconstruct the Merkle root. A verifier recomputes the root from the receipt hash and sibling hashes, then matches it against the checkpoint root.
- Offline verification. With a checkpoint plus an inclusion proof, a third party can confirm a receipt was part of the committed log without access to the full receipt store.
Child Request Receipts (Receipt DAG)
For nested operations (tool calls that spawn child requests), the kernel also produces ChildRequestReceipt records. These track the session, parent request, child request, operation kind, and terminal state, all signed with the same Ed25519 process. Child receipts form a receipt DAG rooted at the originating tool call, linked via parent_request_id.
// Parent receipt (tool call that spawned a nested operation)
{
"id": "019076a3-4b5c-7d8e-9f01-234567890abc",
"tool_name": "run_task",
"action": { "parameters": { "task": "analyze" }, "parameter_hash": "..." },
"decision": { "verdict": "allow" },
...
}
// Child request receipt linked via parent_request_id
{
"id": "019076a3-6d7e-7f01-1234-567890abcdef",
"session_id": "sess_4b8e",
"parent_request_id": "019076a3-4b5c-7d8e-9f01-234567890abc",
"request_id": "req_8f1d",
"operation_kind": "subtool_call",
"terminal_state": "completed",
"outcome_hash": "...",
"policy_hash": "...",
"kernel_key": "...",
"signature": "..."
}| Field | Type | Description |
|---|---|---|
id | string | Unique child request receipt ID |
timestamp | u64 | Unix timestamp (seconds) |
session_id | string | Parent session identifier |
parent_request_id | string | ID of the parent tool call request |
request_id | string | ID of this child request |
operation_kind | enum | Type of operation performed |
terminal_state | enum | Final state of the child operation |
outcome_hash | string | SHA-256 hash of the operation outcome |
policy_hash | string | SHA-256 hash of the policy applied |
kernel_key | PublicKey | Kernel's Ed25519 public key |
signature | Signature | Ed25519 signature over canonical JSON of body |