{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ecoclouddev.com/schemas/eco-receipt.schema.json",
  "title": "EcoCloud Signed Receipt",
  "version": "1.0.0",
  "license": "Apache-2.0",
  "description": "The single, portable envelope every EcoCloud governance kernel returns — a signed, OFFLINE-verifiable record of one governed decision (a constitution verdict, an audit anomaly report, an agent card, a marketing-claim check, a settlement instruction, and so on). A receipt is a typed PAYLOAD object composed with a `content_hash` and a `proof`. The `proof.signature` is an ES256 (ECDSA P-256 / SHA-256) signature over the canonical JSON of the payload alone — the object with `content_hash` and `proof` removed, keys recursively sorted. WIRE FORM: issuing endpoints return the payload nested under a type-specific key together with its detached hash and proof as siblings — e.g. { card, content_hash, proof } or { receipt, content_hash, proof }; this schema describes the composed, self-contained receipt (payload ⊕ content_hash ⊕ proof), and the /verify contract takes the two apart again as { action:'verify', <payload>, proof }. To verify with ZERO calls to EcoCloud: (1) take the payload (strip `content_hash` and `proof` if composed); (2) canonicalize it (recursively sort object keys, arrays kept in order, standard JSON scalar encoding); (3) confirm `content_hash` === sha256hex(canonicalBytes); (4) fetch the JWKS at /.well-known/flowdesk-signing-key.json, select the key whose `kid` equals `proof.kid`, and ECDSA-verify `proof.signature` over the canonical bytes. A valid signature proves the payload is EcoCloud's and unaltered — nothing more. It does NOT certify compliance, approve an action, or move any value; EcoCloud measures and proves, it never holds or transfers value. Try any receipt at /verify/ or by POSTing { action:'verify', … } back to the endpoint that issued it.",
  "type": "object",
  "required": ["typ", "content_hash", "proof"],
  "properties": {
    "v": {
      "type": "integer",
      "minimum": 1,
      "description": "payload schema major version for this `typ`"
    },
    "typ": {
      "type": "string",
      "pattern": "^flowdesk\\.[a-z0-9._-]+$",
      "description": "the record type — selects how to read the payload. See the type registry in the receipt spec; e.g. flowdesk.agent-card, flowdesk.marketing-claim-check, flowdesk.governance-matrix, flowdesk.audit-anomaly-report."
    },
    "version": {
      "type": "string",
      "description": "dated payload version tag, e.g. \"2026-08-03.1\" — human-readable revision of the payload shape for this typ"
    },
    "attested_at": {
      "type": "integer",
      "description": "unix seconds at which the receipt was signed"
    },
    "content_hash": {
      "type": "string",
      "pattern": "^[0-9a-f]{64}$",
      "description": "lowercase hex SHA-256 of the canonical JSON of the payload (this object minus `content_hash` and `proof`). An integrity + de-duplication anchor; recomputable by any verifier."
    },
    "proof": {
      "type": "object",
      "required": ["alg", "kid", "signature"],
      "additionalProperties": true,
      "description": "the detached ES256 signature over canonical(payload)",
      "properties": {
        "alg": {
          "const": "ES256",
          "description": "ECDSA on curve P-256 with SHA-256"
        },
        "kid": {
          "type": "string",
          "description": "id of the signing key within the published JWKS (currently \"flowdesk-envelopes-2026\"); a verifier MUST select the JWKS key by this kid, not by position"
        },
        "signature": {
          "type": "string",
          "description": "base64url of the raw 64-byte ECDSA signature (r||s, 32 bytes each) over the UTF-8 canonical JSON of the payload"
        },
        "jwks": {
          "type": "string",
          "description": "path or URL to the public JWKS that contains the signing key (default /.well-known/flowdesk-signing-key.json)"
        },
        "signed": {
          "type": "string",
          "description": "human note naming exactly which bytes were signed (\"the … object as canonical JSON (recursively sorted keys)\")"
        }
      }
    }
  },
  "additionalProperties": true,
  "$comment": "additionalProperties is true by design: every `typ` extends this envelope with its own payload fields (checks[], verdict, controls, matrix, …). This schema validates the COMMON, signable envelope shared by all EcoCloud receipts; the per-typ payload shape is documented alongside each kernel. The receipt is a measure-and-prove artifact only — it carries no monetary authority."
}
