{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://mandateshield.com/schemas/execution-permit-v1.json",
  "title": "MandateShield Execution Permit JWT Claims v1",
  "description": "Strict decoded claims for an ES256 compact JWT whose protected header is alg=ES256, typ=MSP+JWT and contains a retained MandateShield JWKS kid. Signature verification alone never grants provider submission; the compact token must be claimed online exactly once.",
  "$comment": "Conforming validators additionally enforce nbf <= iat < exp, exp - iat <= 60, settlement_deadline >= exp, exact audience equality and the documented SHA-256 cross-field bindings. JSON Schema cannot express every cross-field invariant.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "iss",
    "aud",
    "jti",
    "iat",
    "nbf",
    "exp",
    "spec",
    "permit_profile",
    "scope",
    "authorization_ref",
    "decision_receipt_id",
    "decision_receipt_hash",
    "input_digest",
    "attempt_digest",
    "protocol",
    "provider",
    "payee",
    "amount",
    "resource",
    "settlement_deadline",
    "max_uses",
    "redemption_uri",
    "one_use_enforced"
  ],
  "properties": {
    "iss": {
      "const": "https://mandateshield.com"
    },
    "aud": {
      "type": "string",
      "minLength": 1,
      "maxLength": 240,
      "description": "One exact PROCESSOR audience. JWT audience arrays are not accepted."
    },
    "jti": {
      "type": "string",
      "pattern": "^msp_[a-f0-9]{32}$",
      "description": "Unique immutable permit identifier."
    },
    "iat": {
      "type": "integer",
      "minimum": 1,
      "description": "JWT NumericDate in whole seconds."
    },
    "nbf": {
      "type": "integer",
      "minimum": 1,
      "description": "JWT NumericDate in whole seconds."
    },
    "exp": {
      "type": "integer",
      "minimum": 1,
      "description": "JWT NumericDate. Normatively no more than 60 seconds after iat; validators must enforce the cross-field lifetime rule."
    },
    "spec": {
      "const": "https://mandateshield.com/specifications/execution-permit/v1"
    },
    "permit_profile": {
      "const": "provider-bound-execution-v1"
    },
    "scope": {
      "const": "payment:execute:one",
      "description": "The permit can authorize only the exact bound submission."
    },
    "authorization_ref": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._:~-]{1,256}$"
    },
    "decision_receipt_id": {
      "type": "string",
      "pattern": "^msr_[a-f0-9]{32}$"
    },
    "decision_receipt_hash": {
      "type": "string",
      "pattern": "^sha256:[a-f0-9]{64}$"
    },
    "input_digest": {
      "type": "string",
      "pattern": "^sha256:[a-f0-9]{64}$"
    },
    "attempt_digest": {
      "type": "string",
      "pattern": "^sha256:[a-f0-9]{64}$"
    },
    "protocol": {
      "type": "string",
      "pattern": "^[A-Z][A-Z0-9_-]{0,31}$"
    },
    "provider": {
      "$ref": "#/$defs/provider"
    },
    "payee": {
      "$ref": "#/$defs/payee"
    },
    "amount": {
      "$ref": "#/$defs/amount"
    },
    "resource": {
      "$ref": "#/$defs/resource"
    },
    "settlement_deadline": {
      "type": "integer",
      "minimum": 1,
      "description": "Execution settlement deadline as a whole-second Unix timestamp. A permit never extends it."
    },
    "max_uses": {
      "const": 1,
      "description": "Normative one-use limit. Only the online atomic claim proves whether this use is still available."
    },
    "redemption_uri": {
      "const": "https://mandateshield.com/api/v2/execution-permits/redeem"
    },
    "one_use_enforced": {
      "const": false,
      "description": "The signed offline artifact cannot prove one-use state. Only a fresh atomic online redemption can return provider_submission_permitted=true."
    }
  },
  "$defs": {
    "provider": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "profile",
        "environment",
        "account",
        "request_id",
        "request_digest",
        "idempotency_key"
      ],
      "properties": {
        "profile": {
          "type": "string",
          "minLength": 1,
          "maxLength": 120
        },
        "environment": {
          "type": "string",
          "enum": [
            "test",
            "live"
          ]
        },
        "account": {
          "type": "string",
          "minLength": 1,
          "maxLength": 240
        },
        "request_id": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._:~-]{1,256}$"
        },
        "request_digest": {
          "type": "string",
          "pattern": "^sha256:[a-f0-9]{64}$"
        },
        "idempotency_key": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._:~-]{1,256}$"
        }
      }
    },
    "payee": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "merchant_id",
        "destination",
        "destination_digest"
      ],
      "properties": {
        "merchant_id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 240
        },
        "destination": {
          "type": "string",
          "minLength": 1,
          "maxLength": 500
        },
        "destination_digest": {
          "type": "string",
          "pattern": "^sha256:[a-f0-9]{64}$",
          "description": "SHA-256 of the exact UTF-8 destination string; validators must recompute it."
        }
      }
    },
    "amount": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "mode",
            "minor_units",
            "currency"
          ],
          "properties": {
            "mode": {
              "const": "ISO_4217"
            },
            "minor_units": {
              "type": "integer",
              "minimum": 1,
              "maximum": 9007199254740991
            },
            "currency": {
              "type": "string",
              "pattern": "^[A-Z]{3}$"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "mode",
            "atomic_units",
            "asset_decimals",
            "asset_id",
            "network"
          ],
          "properties": {
            "mode": {
              "const": "ATOMIC_ASSET"
            },
            "atomic_units": {
              "type": "string",
              "pattern": "^[1-9][0-9]{0,77}$"
            },
            "asset_decimals": {
              "type": "integer",
              "minimum": 0,
              "maximum": 30
            },
            "asset_id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 500
            },
            "network": {
              "type": "string",
              "minLength": 1,
              "maxLength": 240
            }
          }
        }
      ]
    },
    "resource": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "method",
        "uri",
        "body_digest"
      ],
      "properties": {
        "method": {
          "type": "string",
          "pattern": "^[A-Z][A-Z0-9!#$%&'*+.^_`|~-]{0,31}$"
        },
        "uri": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://",
          "maxLength": 2048
        },
        "body_digest": {
          "type": "string",
          "pattern": "^sha256:[a-f0-9]{64}$"
        }
      }
    }
  }
}
