{
  "openapi": "3.1.0",
  "info": {
    "title": "School Derby — public agent surface",
    "version": "1.0.0",
    "summary": "Human routes + public Supabase reads for School Derby",
    "description": "Static SPA at schoolderby.com + Supabase PostgREST public resources. No betting. For routing guidance see https://schoolderby.com/llms.txt and https://schoolderby.com/ai-index.json. Publishable API key is public (same as SPA); never use service_role.",
    "contact": { "name": "School Derby", "url": "https://schoolderby.com" },
    "license": { "name": "Proprietary product surface" }
  },
  "externalDocs": {
    "description": "Agent brief",
    "url": "https://schoolderby.com/llms.txt"
  },
  "servers": [
    { "url": "https://schoolderby.com", "description": "Public website (SPA)" },
    {
      "url": "https://yghyzlgaabgrbpqauczc.supabase.co",
      "description": "Supabase API (use publishable key from SPA / Project Settings → anon/publishable)"
    }
  ],
  "tags": [
    { "name": "site", "description": "HTML SPA routes" },
    { "name": "discovery", "description": "Agent discovery documents" },
    { "name": "public-data", "description": "PostgREST public reads" },
    { "name": "public-rpc", "description": "Public RPCs" }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": ["site"],
        "summary": "Home — Peace Derby public page",
        "description": "Countdown, matchups carousel, calendar, tickets, callouts, squads, streams.",
        "operationId": "getHome",
        "responses": { "200": { "description": "SPA HTML" } }
      }
    },
    "/register": {
      "get": {
        "tags": ["site"],
        "summary": "Register",
        "parameters": [
          {
            "name": "role",
            "in": "query",
            "schema": { "type": "string", "enum": ["student", "official"] }
          }
        ],
        "operationId": "getRegister",
        "responses": { "200": { "description": "Registration SPA" } }
      }
    },
    "/login": {
      "get": {
        "tags": ["site"],
        "summary": "Sign in",
        "operationId": "getLogin",
        "responses": { "200": { "description": "Login SPA" } }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": ["discovery"],
        "summary": "Short LLM brief",
        "operationId": "getLlmsTxt",
        "responses": {
          "200": {
            "description": "text/plain agent instructions",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "tags": ["discovery"],
        "summary": "Full LLM brief",
        "operationId": "getLlmsFull",
        "responses": { "200": { "description": "text/plain" } }
      }
    },
    "/ai-index.json": {
      "get": {
        "tags": ["discovery"],
        "summary": "Machine-readable agent index",
        "operationId": "getAiIndex",
        "responses": { "200": { "description": "JSON discovery index" } }
      }
    },
    "/ai.txt": {
      "get": {
        "tags": ["discovery"],
        "summary": "AI crawler preference file",
        "operationId": "getAiTxt",
        "responses": { "200": { "description": "text/plain" } }
      }
    },
    "/.well-known/agent.json": {
      "get": {
        "tags": ["discovery"],
        "summary": "Agent card",
        "operationId": "getAgentCard",
        "responses": { "200": { "description": "JSON agent card" } }
      }
    },
    "/.well-known/ai-plugin.json": {
      "get": {
        "tags": ["discovery"],
        "summary": "AI plugin manifest (docs pointer)",
        "operationId": "getAiPlugin",
        "responses": { "200": { "description": "JSON manifest" } }
      }
    },
    "/rest/v1/matches": {
      "get": {
        "tags": ["public-data"],
        "summary": "List matches",
        "description": "Public RLS. Filter e.g. status=neq.cancelled",
        "operationId": "listMatches",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" },
            "description": "Supabase publishable/anon key"
          },
          {
            "name": "status",
            "in": "query",
            "schema": { "type": "string" },
            "description": "PostgREST filter, e.g. neq.cancelled"
          },
          {
            "name": "select",
            "in": "query",
            "schema": { "type": "string", "default": "*" }
          }
        ],
        "responses": { "200": { "description": "JSON array of matches" } }
      }
    },
    "/rest/v1/public_callouts": {
      "get": {
        "tags": ["public-data"],
        "summary": "Public callout board",
        "operationId": "listPublicCallouts",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": { "200": { "description": "Callouts with backing_count" } }
      }
    },
    "/rest/v1/public_squads": {
      "get": {
        "tags": ["public-data"],
        "summary": "Verified public squad rows",
        "operationId": "listPublicSquads",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "match_id",
            "in": "query",
            "schema": { "type": "string" },
            "description": "eq.{uuid}"
          }
        ],
        "responses": { "200": { "description": "Squad list" } }
      }
    },
    "/rest/v1/ticket_types": {
      "get": {
        "tags": ["public-data"],
        "summary": "Active ticket tiers",
        "operationId": "listTicketTypes",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "active",
            "in": "query",
            "schema": { "type": "string", "example": "eq.true" }
          }
        ],
        "responses": { "200": { "description": "Ticket types (prices in kobo)" } }
      }
    },
    "/rest/v1/rpc/search_school_directory": {
      "post": {
        "tags": ["public-rpc"],
        "summary": "Search nationwide secondary school directory",
        "operationId": "searchSchoolDirectory",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "p_query": { "type": "string", "nullable": true },
                  "p_state": { "type": "string", "nullable": true },
                  "p_limit": { "type": "integer", "default": 20 },
                  "p_offset": { "type": "integer", "default": 0 }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Directory hits" } }
      }
    },
    "/rest/v1/rpc/list_school_directory_states": {
      "post": {
        "tags": ["public-rpc"],
        "summary": "List states in school directory",
        "operationId": "listSchoolDirectoryStates",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": { "200": { "description": "Array of { state }" } }
      }
    },
    "/rest/v1/rpc/create_ticket_order": {
      "post": {
        "tags": ["public-rpc"],
        "summary": "Create pending ticket order",
        "description": "Only with explicit user consent — collects buyer name/email/phone. Not payment capture.",
        "operationId": "createTicketOrder",
        "servers": [
          { "url": "https://yghyzlgaabgrbpqauczc.supabase.co" }
        ],
        "parameters": [
          {
            "name": "apikey",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["p_ticket_type_id", "p_quantity", "p_buyer_name"],
                "properties": {
                  "p_ticket_type_id": { "type": "string", "format": "uuid" },
                  "p_quantity": { "type": "integer", "minimum": 1 },
                  "p_buyer_name": { "type": "string" },
                  "p_buyer_email": { "type": "string", "nullable": true },
                  "p_buyer_phone": { "type": "string", "nullable": true }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON with order_id, amount_kobo, currency"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "supabasePublishable": {
        "type": "apiKey",
        "in": "header",
        "name": "apikey",
        "description": "Supabase publishable/anon key (public). Also send Authorization: Bearer <same key>."
      }
    }
  }
}
