{
  "$id": "https://KATA.org/schemas/intent-mandate.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "KATA Intent Mandate",
  "description": "Immutable signed intent bound to one agent key. The principal's signature covers the intent, the limits, the human-readable rendering, and the agent key. Status: Concept / Open Design — not production ready. The agreement record that carries this mandate is schemas/agreement.json. amounts stay major units, as in schemas/intent.json.",
  "type": "object",
  "additionalProperties": false,
  "required": ["mandate_id", "version", "principal", "agent", "intent"],
  "properties": {
    "mandate_id": {
      "type": "string",
      "description": "Identifier of this mandate version. A new version uses a new mandate_id."
    },
    "version": {
      "type": "integer",
      "minimum": 1,
      "description": "Mandate version. Amendments increment it. intent.version is kept equal to it."
    },
    "supersedes": {
      "type": "string",
      "pattern": "^sha256:[0-9a-f]{64}$",
      "description": "Hash of the signing document of the mandate version this one replaces."
    },
    "principal": {
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "id"],
      "properties": {
        "type": {
          "type": "string",
          "enum": ["human", "business", "institution", "system", "agent"]
        },
        "id": { "type": "string" },
        "display_name": { "type": "string" },
        "public_key": { "$ref": "#/$defs/publicJwk" }
      }
    },
    "algorithm": {
      "type": "string",
      "enum": ["EdDSA", "ES256"],
      "description": "Signature algorithm. EdDSA is Ed25519. ES256 is ECDSA P-256 with SHA-256. The JWS header alg is this value."
    },
    "confirmation_language": {
      "type": "string",
      "description": "Language of the canonical confirmation text KATA produces. en is built in. The wallet displays this text and does not replace it."
    },
    "agent": {
      "type": "object",
      "additionalProperties": false,
      "required": ["agent_id", "public_key_fingerprint"],
      "properties": {
        "agent_id": { "type": "string" },
        "public_key_fingerprint": {
          "type": "string",
          "pattern": "^sha256:[0-9a-f]{64}$",
          "description": "SHA-256 of the raw public key. Ed25519 uses the 32-byte key. P-256 uses the 64-byte x||y."
        },
        "public_key": { "$ref": "#/$defs/publicJwk" }
      }
    },
    "delegation_id": {
      "type": "string",
      "description": "Delegation this mandate is stored inside."
    },
    "parent_limits": {
      "$ref": "#/$defs/parentLimits",
      "description": "Signed copy of the agreement parent set. This intent must not exceed it."
    },
    "intent": {
      "$ref": "intent.json",
      "description": "Structured intent. maximum_amount is the per-transaction ceiling."
    },
    "limits": { "$ref": "#/$defs/limits" },
    "not_before": { "type": "string", "format": "date-time" },
    "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the mandate lapses. When intent.time_limit is also set, the two are the same instant."
    },
    "required_acknowledgements": {
      "type": "array",
      "items": { "type": "string", "enum": ["agent", "merchant", "psp", "issuer"] },
      "description": "Roles that must countersign before the agreement is active."
    },
    "revocation_endpoint": {
      "type": "string",
      "description": "Where a verifier reads revocation status. The reference library does not fetch it. If this is set, evaluation steps up until the caller says the endpoint was checked."
    },
    "rendering": {
      "type": "object",
      "additionalProperties": false,
      "required": ["text", "hash"],
      "properties": {
        "text": {
          "type": "string",
          "description": "Confirmation the principal signed, in any language. The hash is SHA-256 of these exact bytes. The default English rendering is used only when the signer does not supply text."
        },
        "hash": {
          "type": "string",
          "pattern": "^sha256:[0-9a-f]{64}$",
          "description": "SHA-256 of the UTF-8 rendering text."
        }
      }
    },
    "signature": { "$ref": "#/$defs/jws" }
  },
  "$defs": {
    "publicJwk": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["kty", "crv", "x"],
          "properties": {
            "kty": { "const": "OKP" },
            "crv": { "const": "Ed25519" },
            "x": { "type": "string" },
            "kid": { "type": "string" }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["kty", "crv", "x", "y"],
          "properties": {
            "kty": { "const": "EC" },
            "crv": { "const": "P-256" },
            "x": { "type": "string" },
            "y": { "type": "string" },
            "kid": { "type": "string" }
          }
        }
      ],
      "description": "Public JWK for Ed25519 (OKP) or P-256 (EC). The private parameter d is not a member of this object."
    },
    "jws": {
      "type": "object",
      "additionalProperties": false,
      "required": ["protected", "payload", "signature"],
      "properties": {
        "protected": { "type": "string" },
        "payload": { "type": "string" },
        "signature": { "type": "string" }
      },
      "description": "Flattened JWS (RFC 7515), alg EdDSA or ES256. Protected header and payload are KATA canonical JSON."
    },
    "parentLimits": {
      "type": "object",
      "additionalProperties": false,
      "description": "The parent set for every live intent. Per-transaction ceilings are not added together. Cumulative slices are.",
      "properties": {
        "allowed_actions": { "type": "array", "items": { "type": "string" } },
        "category": { "type": "string" },
        "cumulative_maximum": { "type": "number", "minimum": 0 },
        "currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
        "expires_at": { "type": "string", "format": "date-time" },
        "maximum_amount": { "type": "number", "minimum": 0 },
        "merchant_constraints": { "type": "array", "items": { "type": "string" } },
        "purpose": { "type": "string" }
      }
    },
    "limits": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
        "per_transaction_maximum": {
          "type": "number",
          "minimum": 0,
          "description": "Restatement of intent.maximum_amount. The two must be equal. This is not a second ceiling."
        },
        "cumulative_maximum": {
          "type": "number",
          "minimum": 0,
          "description": "This intent's slice of the parent total. Distinct from the per-transaction ceiling. KATA records spend on the agreement ledger."
        },
        "frequency": {
          "type": "object",
          "additionalProperties": false,
          "required": ["max_count", "per"],
          "properties": {
            "max_count": { "type": "integer", "minimum": 1 },
            "per": {
              "type": "string",
              "enum": ["agreement", "P1D", "P7D", "P1M"],
              "description": "agreement is the whole window. P1D is one day, P7D is seven days, P1M is thirty days."
            }
          }
        },
        "merchant_denylist": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Merchants refused even when merchant_constraints is empty. Empty merchant_constraints still means no allowlist."
        }
      }
    }
  }
}
