DEOS Receipt Format — v1 Specification

Status: v1.0 — published 2026-05-02 Spec URI: https://projectmaya.deoscomputing.io/receipts/format/v1 Maintainer: DEOS Computing (did:web:deos.computing) Schema identifier: deos_receipt_v1 Canonicalization: RFC 8785 (JSON Canonicalization Scheme, JCS) Hash: BLAKE3-256 Default signature: Ed25519

A receipt is a signed, tamper-evident assertion that a specific agent took a specific action on behalf of a specific principal under a specific capability, with these specific inputs and outputs. Receipts are the substrate's load-bearing surface — every other layer either produces or verifies them.

This document is normative for v1. Implementations MUST conform exactly to interoperate.


1. Goals

A v1 receipt must:

  1. Be canonically serializable so that any compliant implementation produces byte-identical output for the same input.
  2. Be content-addressable — the receipt's id is the BLAKE3 hash of its canonical bytes.
  3. Bind a chain of accountability: substrate → agent → principal → capability → action → output.
  4. Link to replay: contain enough information to fetch a full replay bundle and verify byte-for-byte equivalence.
  5. Be time-anchorable: be includable in a Merkle log whose root is anchored to a public timestamp service (M5).
  6. Be independently verifiable: a third party with only the spec and the receipt can verify everything except replay (which additionally requires fetching the bundle).

A v1 receipt explicitly does not carry:

2. Schema

A receipt is a JSON object with the following top-level fields:

{
  "v": 1,
  "schema": "deos_receipt_v1",
  "id": "<32-byte BLAKE3 hex of canonical receipt minus the id and signatures fields>",
  "issued_at": <unix nanos, integer>,
  "issuer": "<DID of the substrate node that issued the receipt>",
  "subject": "<DID of the agent that performed the action>",
  "principal": "<DID of the human/org on whose behalf the agent acted>",
  "capability": {
    "id": "<32-byte BLAKE3 hex of root capability>",
    "chain": [ /* UCAN tokens, root-first, see §5 */ ],
    "scope": { /* resolved scope after applying caveats; see §5.3 */ }
  },
  "action": {
    "type": "<see §6>",
    "code_hash": "<BLAKE3 hex of the executable code that ran>",
    "inputs_hash": "<BLAKE3 hex of canonical-serialized inputs>",
    "outputs_hash": "<BLAKE3 hex of canonical-serialized outputs>",
    "metadata": { /* action-type-specific; see §6 */ }
  },
  "replay": {
    "bundle_uri": "<absolute URI of the replay bundle, optional>",
    "bundle_hash": "<BLAKE3 hex of the replay bundle, optional>",
    "deterministic": true
  },
  "log": {
    "tree_id": "<identifier of the Merkle log this receipt is appended to>",
    "leaf_index": <integer, 0-based>,
    "root": "<BLAKE3 hex of the log root at the time of inclusion, optional>"
  },
  "anchors": [
    { "service": "opentimestamps", "proof": "<base64>" }
  ],
  "signatures": [
    {
      "kid": "<DID URL with key fragment, e.g. did:deos:abc#sig-1>",
      "alg": "ed25519",
      "sig": "<base64-url-nopad of 64-byte Ed25519 signature>"
    }
  ]
}

2.1 Required vs optional fields

Field Required Notes
v yes MUST equal 1 for this spec.
schema yes MUST equal "deos_receipt_v1".
id yes Computed (§4); not signed itself.
issued_at yes Unix nanoseconds; MUST be monotonic per issuer.
issuer yes DID.
subject yes DID of the acting agent.
principal yes DID of the entity ultimately accountable. May equal subject for autonomous agents acting on their own behalf.
capability.id yes Hash of the root capability.
capability.chain yes Non-empty UCAN chain, root-first.
capability.scope yes Resolved scope after caveat evaluation.
action.type yes See §6.
action.code_hash yes BLAKE3 of executable; for non-executable actions, MUST be the all-zero hash.
action.inputs_hash yes BLAKE3 of canonical inputs; if no inputs, all-zero hash.
action.outputs_hash yes BLAKE3 of canonical outputs; if no outputs, all-zero hash.
action.metadata yes Object; MAY be empty {}.
replay.deterministic yes Boolean. v1 status: producers MAY claim true but the substrate-managed replay-bundle pipeline is not in v1; treat as informational.
replay.bundle_uri optional Producer-managed in v1 (substrate does not host bundles). MUST be a valid URI if present. v2 will introduce substrate-managed CAS-backed bundle storage.
replay.bundle_hash optional BLAKE3 hex of the bundle pointed to by bundle_uri. MUST be present if bundle_uri is present.
log.tree_id yes
log.leaf_index yes
log.root optional Snapshot at time of inclusion. Verifier may also fetch via attestation API.
anchors optional Array, MAY be empty.
signatures yes Non-empty. At least one signature MUST be by the issuer.

2.2 Strict typing

3. Action types (v1)

The action.type field is a registered string. v1 reserves these values:

type Meaning Required metadata keys
tool_call An MCP-style tool invocation tool_name, server_did
payment_intent An authorization to settle funds from, to, amount, currency
payment_settlement Evidence of completed settlement intent_receipt_id, rail, external_ref
identity_claim An attestation about an identity claim_type, evidence_hash
message_send An outbound message to, transport, content_hash
code_execution Generic deterministic code run program_did, args_hash, exit_code
policy_evaluation A policy decision (allow/deny) policy_id, decision, reason

Implementations MAY emit receipts with an unregistered action.type, but MUST prefix it with x- (e.g. x-vendor.thing). Verifiers SHOULD pass through unknown x- types without rejecting.

4. Canonicalization & receipt id

4.1 Canonical form

Receipts are canonicalized with RFC 8785 (JCS), with one deliberate divergence on key ordering:

4.2 Computing id

The id is computed over the receipt with the id and signatures fields removed:

canonical_receipt_for_id = JCS(receipt minus { id, signatures })
id = lowercase_hex(BLAKE3-256(canonical_receipt_for_id))

The id is therefore stable across re-signing and is determined solely by content.

4.3 Signing

Each signature signs the canonical receipt with id present but with the signatures array removed:

canonical_receipt_for_sig = JCS(receipt minus { signatures })
sig_payload = "deos-receipt-v1:" || canonical_receipt_for_sig    (concatenation, no separator beyond the colon)
sig.sig    = base64url_nopad(Ed25519_sign(private_key, sig_payload))

The "deos-receipt-v1:" prefix is a domain-separation tag. Verifiers MUST include it.

The bare-string concatenation is unambiguous because every registered tag in /registry/v1 §6 is colon-terminated and prefix-free, and canonical JSON bodies never begin with :. See /registry/v1 §6.1 for the formal invariant and the CI test that enforces it. v2 may switch to length-prefix framing for explicit safety; v1 relies on the registry-managed invariant.

4.4 Verification

To verify a receipt:

  1. Recompute id per §4.2 and check it matches the id field.
  2. For each signature in signatures:
    • Resolve kid to a public key via the DID document.
    • Construct sig_payload per §4.3.
    • Verify sig over sig_payload with the public key.
  3. At least one signature with kid belonging to the issuer MUST verify.
  4. Verify the capability chain (§5.4).
  5. If a log inclusion proof is being checked (M2), verify it against the published root.
  6. If an anchor proof is present, verify it (M5).
  7. If replay verification is requested, fetch the bundle and re-execute (M3).

5. Capability chain

5.1 Format

capability.chain is a non-empty array of UCAN-shaped JSON tokens, root-first. The full normative format is specified in /ucan/tokens/v1.

Briefly, each token has these fields:

Tokens are NOT JWT-encoded; they are inline canonical JSON within the receipt. Wire-compatibility-via-translation with UCAN v1.0 is described in /ucan/tokens/v1 §7.

5.2 Chain validity

The chain validation rules are normative in /ucan/tokens/v1 §4. Summary:

  1. Per-token signature verifies; s.kid belongs to iss.
  2. Chain continuity: chain[0].iss == receipt.principal, chain[i].aud == chain[i+1].iss, chain[last].aud == receipt.subject.
  3. Every token's [nbf, exp] window covers receipt.issued_at.
  4. Each child attenuation narrows-or-equal to a parent attenuation.
  5. The composed leaf scope satisfies the receipt's action (v1: shape-level, plus payment_intent.metadata.amount <= max for spend caveats).
  6. (M7) No token in the chain appears in the revocation log.

5.3 Resolved scope

capability.scope is the intersection of all attenuations in the chain, evaluated against any caveats (M6). It is an opaque object whose schema depends on the action type. Verifiers MUST recompute scope from the chain and check that it matches capability.scope.

5.4 Capability id

capability.id is BLAKE3(JCS(capability.chain[0])) — the root token's content hash. It is the stable identifier for "this line of authority."

6. Action metadata schemas

For each registered action.type, the metadata object SHOULD conform to:

6.1 tool_call

{
  "tool_name": "<string>",
  "server_did": "<DID of the MCP server>",
  "request_id": "<optional, opaque>"
}

6.2 payment_intent

{
  "from": "<DID of payer>",
  "to": "<DID or other identifier of payee>",
  "amount": "<decimal string, e.g. \"42.50\">",
  "currency": "<ISO 4217 or chain-asset, e.g. \"USD\", \"USDC.base\">",
  "rail_hint": "<optional, e.g. \"fednow\", \"ach\", \"erc20\">"
}

6.3 payment_settlement

{
  "intent_receipt_id": "<receipt id of the original payment_intent>",
  "rail": "<the actual settlement rail used>",
  "external_ref": "<rail-specific reference, e.g. tx hash or ACH trace>",
  "settled_at_ns": <unix nanos>
}

6.4 identity_claim

{
  "claim_type": "<string, e.g. \"email_verified\", \"over_18\">",
  "claim_subject": "<DID of the entity the claim is about>",
  "evidence_hash": "<BLAKE3 hex of evidence; evidence stored separately>"
}

6.5 message_send

{
  "to": "<DID or address of recipient>",
  "transport": "<e.g. \"smtp\", \"signal\", \"deos-msg\">",
  "content_hash": "<BLAKE3 hex of canonical message content>",
  "thread_id": "<optional, opaque>"
}

6.6 code_execution

{
  "program_did": "<DID of the program>",
  "args_hash": "<BLAKE3 hex>",
  "exit_code": <integer>,
  "duration_ns": <integer, optional>
}

6.7 policy_evaluation

{
  "policy_id": "<BLAKE3 hex of canonical policy>",
  "decision": "<\"allow\" | \"deny\" | \"approve_required\">",
  "reason": "<short string>",
  "matched_rule_id": "<optional>"
}

7. Versioning

8. Test vectors

Test vectors covering the canonical-encoding and signature-verification surface ship with the reference implementation. v1 covers:

Each vector includes:

Independent implementations are expected to round-trip these vectors before claiming v1 conformance. Vectors are available from DEOS Computing on request during the v1 alpha.

9. Wire transport

Receipts travel over:

Receipts SHOULD be transported as canonical bytes whenever possible to avoid re-canonicalization at verification time. Implementations MAY emit pretty-printed JSON for human inspection but MUST canonicalize before hashing or signing.

10. Security considerations

10.1 Replay (network) attacks

The receipt's issued_at and the capability chain's nbf/exp bound the validity window. The Merkle log (M2) provides ordering. The OTS anchor (M5) provides time-of-existence-by-T against a public timeline.

10.2 Key compromise

If an issuer's signing key is compromised, all receipts signed after the compromise are suspect. Mitigation: short-lived keys (rotated frequently), key revocation log (M7), and audit log of kid usage.

10.3 Replay bundle availability

A receipt without an accessible bundle is verifiable as to signatures and chain, but not as to byte-for-byte execution equivalence. Verifiers MUST treat "bundle unavailable" distinctly from "bundle present and mismatched."

10.4 Capability scope leakage

capability.scope exposes resolved permissions. For privacy-sensitive actions, scope SHOULD be expressed as a hash commitment with selective-disclosure proofs (deferred to v1.1).

10.5 Hash algorithm agility

v1 hardcodes BLAKE3-256. v2 will introduce algorithm negotiation if BLAKE3 is broken or superseded. Implementations SHOULD treat the hash algorithm as a v-bound choice, not a runtime parameter.

11. Open questions deferred to v1.1


12. Maintainer

DEOS Computing — design questions, conformance reports, and proposed additions to github.com/DEOS-Computing.

License: CC BY 4.0 (text), Apache-2.0 (reference code).