{
  "openapi": "3.1.0",
  "info": {
    "title": "StructureClerk Authority API",
    "version": "0.1.0",
    "summary": "Advisory policy decisions for AI agents, with signed evidence.",
    "description": "Decide whether an AI agent may execute an action — ALLOW, DENY, APPROVE or ESCALATE — across 190 jurisdictions, and verify any decision afterwards. Decisions are advisory: StructureClerk decides, your infrastructure enforces. This specification is published under the MIT license; the application implementing it is not open source.",
    "license": { "name": "MIT", "url": "https://structureclerk.ca/spec/LICENSE" },
    "contact": { "email": "info@structureclerk.ca", "url": "https://structureclerk.ca/authority" }
  },
  "servers": [{ "url": "https://structureclerk.ca" }],
  "paths": {
    "/api/v1/authority/decide": {
      "post": {
        "operationId": "decide",
        "summary": "Render an advisory authority decision",
        "description": "Public and unauthenticated for generic decisions. Supplying org_profile_id modulates the decision with an organisation's assessed posture and requires an authenticated, entitled session that owns that profile.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "https://structureclerk.ca/spec/authority-decision-v0.1.schema.json#/$defs/request" },
              "examples": {
                "healthPayment": {
                  "summary": "Payment involving health data in Quebec",
                  "value": {
                    "agent": { "id": "financebot-01", "autonomy_level": 3 },
                    "action": {
                      "type": "payment.execute",
                      "amount": 12500,
                      "currency": "CAD",
                      "data_categories": ["personal", "health"]
                    },
                    "context": { "jurisdictions": ["QC"], "sector": "health" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decision rendered",
            "content": {
              "application/json": {
                "schema": { "$ref": "https://structureclerk.ca/spec/authority-decision-v0.1.schema.json#/$defs/response" }
              }
            }
          },
          "400": { "description": "Invalid request; body carries an errors array" },
          "401": { "description": "org_profile_id supplied without an authenticated session" },
          "403": { "description": "org_profile_id supplied without the required entitlement" },
          "404": { "description": "Profile not found, or not owned by the caller" },
          "413": { "description": "Request body too large" },
          "429": { "description": "Rate limited" }
        }
      },
      "options": { "operationId": "decidePreflight", "summary": "CORS preflight", "responses": { "204": { "description": "No content" } } }
    },
    "/api/v1/authority/verify/{evidence_id}": {
      "get": {
        "operationId": "verifyEvidence",
        "summary": "Verify a decision's evidence",
        "description": "Public. Returns the signature, its validity, and the decision's position in the append-only chained log. Never returns the original request payload.",
        "parameters": [
          {
            "name": "evidence_id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "pattern": "^EVD-" }
          },
          {
            "name": "sha256",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
            "description": "Your independently recomputed hash; the response reports whether it matches."
          }
        ],
        "responses": {
          "200": { "description": "Verification result" },
          "400": { "description": "Malformed evidence id" },
          "404": { "description": "Unknown evidence id" },
          "503": { "description": "Ledger storage unavailable" }
        }
      }
    },
    "/api/v1/authority/verify/chain": {
      "get": {
        "operationId": "replayChain",
        "summary": "Replay the evidence ledger",
        "description": "Public. Returns chain metadata so a third party can recompute every link independently. Ledger order is append order, not decision order.",
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "integer", "minimum": 1 } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 500 } }
        ],
        "responses": { "200": { "description": "Chain entries" } }
      }
    },
    "/.well-known/structureclerk-authority.json": {
      "get": {
        "operationId": "publicKeys",
        "summary": "Published signing keys",
        "description": "Ed25519 public keys in JWK form, plus the canonicalization rules needed to recompute an evidence hash. Returns an empty key list with status 'unconfigured' when signing is not enabled.",
        "responses": { "200": { "description": "Key document" } }
      }
    }
  }
}
