{
  "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 — using regulatory mapping across 192 jurisdictions for data protection, 18 for AI governance and 5 for cybersecurity, 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"
                      ],
                      "destination_jurisdiction": "US_FED"
                    },
                    "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"
          },
          "402": {
            "description": "insufficient_credits — the account's prepaid balance cannot cover this call."
          },
          "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"
          },
          "503": {
            "description": "metering_unavailable — the usage counter is down; anonymous calls are refused rather than served free."
          }
        },
        "security": [
          {},
          {
            "bearerAuth": []
          }
        ]
      },
      "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"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Optional. Calls answer anonymously within a daily free allowance (see GET /api/v1/pricing). Past it, send an API key created at /dashboard/api-keys: Authorization: Bearer sk_sc_<64 hex>. Calls then draw on the account's prepaid credit balance."
      }
    }
  }
}
