{
  "openapi": "3.1.0",
  "info": {
    "title": "XispeScore Public API",
    "version": "1.0.0",
    "description": "Public, read-only API for discovering XispeScore and published sports competitions. Major API versions are encoded in URL paths. Error responses use a stable typed JSON envelope. Rate-limit and lifecycle conventions are documented at /developers/versioning.",
    "contact": {
      "name": "XispeScore",
      "email": "xispescore@gmail.com",
      "url": "https://xispescore.vercel.app/contact"
    },
    "x-versioning-policy": "https://xispescore.vercel.app/developers/versioning"
  },
  "externalDocs": {
    "description": "XispeScore Developers",
    "url": "https://xispescore.vercel.app/developers"
  },
  "servers": [
    {
      "url": "https://xispescore.vercel.app",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Discovery",
      "description": "Agent and developer discovery endpoints."
    },
    {
      "name": "Competitions",
      "description": "Read-only access to published competitions."
    }
  ],
  "paths": {
    "/api/public/v1/site": {
      "get": {
        "tags": ["Discovery"],
        "summary": "Get XispeScore public integration information",
        "description": "Returns product identity and canonical links to the public API, OpenAPI document, versioning policy, agent instructions and MCP endpoint.",
        "operationId": "getXispeScoreSiteInfo",
        "responses": {
          "200": {
            "description": "Public integration information.",
            "headers": {
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
              "RateLimit": { "$ref": "#/components/headers/RateLimit" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SiteInfo" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/public/v1/competitions": {
      "get": {
        "tags": ["Competitions"],
        "summary": "List published competitions",
        "description": "Lists public XispeScore competitions. Results are read-only and may be filtered by sport.",
        "operationId": "listPublishedCompetitions",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of competitions to return.",
            "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
          },
          {
            "name": "sport",
            "in": "query",
            "required": false,
            "description": "Optional sport identifier, for example football or futsal.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 40 }
          }
        ],
        "responses": {
          "200": {
            "description": "Published competitions.",
            "headers": {
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
              "RateLimit": { "$ref": "#/components/headers/RateLimit" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CompetitionList" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/api/public/v1/competitions/{id}": {
      "get": {
        "tags": ["Competitions"],
        "summary": "Get a published competition",
        "description": "Returns basic public metadata for one published XispeScore competition.",
        "operationId": "getPublishedCompetition",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Competition identifier.",
            "schema": { "type": "string", "minLength": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "Published competition.",
            "headers": {
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
              "RateLimit": { "$ref": "#/components/headers/RateLimit" },
              "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
              "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
              "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
              "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CompetitionSummary" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimitPolicy": {
        "description": "Structured public quota policy. The current default is 120 requests per 60 seconds.",
        "schema": { "type": "string" }
      },
      "RateLimit": {
        "description": "Current structured rate-limit state including remaining requests and time to reset.",
        "schema": { "type": "string" }
      },
      "RateLimitLimit": {
        "description": "Compatibility field containing the numeric request limit.",
        "schema": { "type": "integer", "minimum": 1 }
      },
      "RateLimitRemaining": {
        "description": "Compatibility field containing requests remaining in the current window.",
        "schema": { "type": "integer", "minimum": 0 }
      },
      "RateLimitReset": {
        "description": "Compatibility field containing seconds until the current window resets.",
        "schema": { "type": "integer", "minimum": 0 }
      },
      "RetryAfter": {
        "description": "Seconds the client should wait before retrying after a 429 response.",
        "schema": { "type": "integer", "minimum": 1 }
      },
      "DeprecationPolicyLink": {
        "description": "Link to the XispeScore API versioning and deprecation policy. The link alone does not mean the current endpoint is deprecated.",
        "schema": { "type": "string" }
      }
    },
    "schemas": {
      "SiteInfo": {
        "type": "object",
        "additionalProperties": false,
        "required": ["name", "description", "url", "openapi", "documentation", "versioningPolicy", "llms", "agentInstructions", "mcp"],
        "properties": {
          "name": { "type": "string", "const": "XispeScore" },
          "description": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "openapi": { "type": "string", "format": "uri" },
          "documentation": { "type": "string", "format": "uri" },
          "versioningPolicy": { "type": "string", "format": "uri" },
          "llms": { "type": "string", "format": "uri" },
          "agentInstructions": { "type": "string", "format": "uri" },
          "mcp": { "type": "string", "format": "uri" }
        }
      },
      "CompetitionSummary": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "name", "sport", "updatedAt"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "sport": { "type": "string" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "CompetitionList": {
        "type": "object",
        "additionalProperties": false,
        "required": ["items", "count"],
        "properties": {
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/CompetitionSummary" } },
          "count": { "type": "integer", "minimum": 0 }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": ["code", "message", "hint", "status"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "hint": { "type": "string" },
              "status": { "type": "integer", "minimum": 400, "maximum": 599 }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request parameters are invalid.",
        "headers": {
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
          "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "invalidLimit": {
                "value": {
                  "error": {
                    "code": "INVALID_LIMIT",
                    "message": "The limit parameter must be an integer between 1 and 100.",
                    "hint": "Use a value from 1 to 100 or omit the parameter.",
                    "status": 400
                  }
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested public resource does not exist.",
        "headers": {
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
          "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "TooManyRequests": {
        "description": "The public API quota has been exhausted for the current window.",
        "headers": {
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" },
          "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
          "RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" },
          "Retry-After": { "$ref": "#/components/headers/RetryAfter" },
          "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "examples": {
              "quotaExceeded": {
                "value": {
                  "error": {
                    "code": "RATE_LIMIT_EXCEEDED",
                    "message": "The public API request limit has been exceeded.",
                    "hint": "Wait for Retry-After seconds before retrying.",
                    "status": 429
                  }
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "The server could not complete the request.",
        "headers": {
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" },
          "Link": { "$ref": "#/components/headers/DeprecationPolicyLink" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    }
  }
}
