{
  "openapi": "3.1.0",
  "info": {
    "title": "GlueBolt API",
    "version": "1.0.0",
    "description": "The qualification gate for teams commanding AI. Read a member's certification tier, propose governed actions on their behalf, execute only after human consent. Every call lands in the account's audit ledger; a denial is a ledger row, not an error. MCP variant of the same gate: POST /api/mcp (Streamable HTTP, same Bearer auth)."
  },
  "servers": [{ "url": "https://gluebolt.com" }],
  "security": [{ "apiKey": [] }],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Account-scoped key minted in the GlueBolt console (gbk_...). The key authenticates the account; each call names the member the agent acts for."
      }
    },
    "schemas": {
      "Actor": {
        "type": "object",
        "description": "The member the agent is acting for. Give email, or provider+external_id.",
        "properties": {
          "email": { "type": "string", "description": "Shorthand for provider=email." },
          "provider": { "type": "string", "enum": ["email", "slack"] },
          "external_id": { "type": "string" }
        }
      },
      "Capability": {
        "type": "object",
        "properties": {
          "member": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "email": { "type": ["string", "null"] },
              "providers": { "type": "array", "items": { "type": "string" } }
            }
          },
          "tier": { "type": "string", "enum": ["read_only", "guarded_write", "write"] },
          "tier_source": { "type": "string" },
          "certified": { "type": "boolean" },
          "certifications": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "curriculum": { "type": "string" },
                "title": { "type": "string" },
                "certified": { "type": "boolean" },
                "modules_passed": { "type": "integer" },
                "modules_total": { "type": "integer" },
                "last_passed_at": { "type": ["string", "null"], "format": "date-time" }
              }
            }
          }
        }
      },
      "ActionRequest": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "kind": { "type": "string", "enum": ["broadcast"] },
          "status": { "type": "string", "enum": ["proposed", "denied", "cancelled", "executed"] },
          "member": { "type": "string" },
          "tier_at_request": { "type": "string" },
          "source": { "type": "string" },
          "payload": { "type": "object" },
          "created_at": { "type": "string", "format": "date-time" },
          "denial_reason": { "type": "string" },
          "requires_confirmation": { "type": "boolean" },
          "blast_radius": {
            "type": "object",
            "properties": {
              "slack": { "type": "integer" },
              "email": { "type": "integer" },
              "unreachable": { "type": "integer" }
            }
          },
          "result": { "type": "object" },
          "executed_at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } }
      }
    }
  },
  "paths": {
    "/api/v1/capability": {
      "get": {
        "summary": "Is this human qualified? Tier + certification record for one member.",
        "parameters": [
          { "name": "email", "in": "query", "schema": { "type": "string" }, "description": "Shorthand for provider=email." },
          { "name": "provider", "in": "query", "schema": { "type": "string", "enum": ["email", "slack"] } },
          { "name": "external_id", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "The member's capability.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Capability" } } } },
          "404": { "description": "No member with that identity.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/v1/actions": {
      "get": {
        "summary": "The audit ledger, oldest first.",
        "parameters": [{ "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } }],
        "responses": { "200": { "description": "Ledger rows.", "content": { "application/json": { "schema": { "type": "object", "properties": { "actions": { "type": "array", "items": { "$ref": "#/components/schemas/ActionRequest" } } } } } } } }
      },
      "post": {
        "summary": "Propose a governed action for a member. Returns denied (tier insufficient) or proposed (confirm to execute). Both are audit rows; nothing executes at propose time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["kind", "actor", "payload"],
                "properties": {
                  "kind": { "type": "string", "enum": ["broadcast"] },
                  "actor": { "$ref": "#/components/schemas/Actor" },
                  "payload": { "type": "object", "properties": { "message": { "type": "string" } }, "required": ["message"] }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "The ledger row: status is denied or proposed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActionRequest" } } } },
          "404": { "description": "Unknown actor.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Unknown kind or missing payload.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/v1/actions/{id}": {
      "get": {
        "summary": "One ledger row.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": { "description": "The row.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActionRequest" } } } },
          "404": { "description": "No such action.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/v1/actions/{id}/confirm": {
      "post": {
        "summary": "Execute a proposed action. Call only after the proposing member has seen the blast radius and explicitly consented; proposer-only.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["actor"], "properties": { "actor": { "$ref": "#/components/schemas/Actor" } } } } } },
        "responses": {
          "200": { "description": "Executed; result has per-channel delivery counts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActionRequest" } } } },
          "403": { "description": "Actor is not the proposer.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "409": { "description": "Already executed, cancelled or denied.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/v1/actions/{id}/cancel": {
      "post": {
        "summary": "Abandon a proposed action; proposer-only. Recorded in the ledger.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["actor"], "properties": { "actor": { "$ref": "#/components/schemas/Actor" } } } } } },
        "responses": {
          "200": { "description": "Cancelled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ActionRequest" } } } },
          "403": { "description": "Actor is not the proposer.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "409": { "description": "Not in a proposable state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  }
}
