{
  "openapi": "3.1.1",
  "info": {
    "title": "Tipsme Football Data API",
    "version": "1.0.0",
    "description": "Live scores, fixtures, match detail, odds including HKJC, and AI match analysis. Docs: https://tipsme.hk/developers/docs"
  },
  "servers": [
    {
      "url": "https://api.tipsme.hk"
    }
  ],
  "paths": {
    "/v1/football/meta/limits": {
      "get": {
        "tags": [
          "meta"
        ],
        "operationId": "GetLimits",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfIReadOnlyListOfTierLimitsDto"
                }
              }
            }
          }
        }
      }
    },
    "/v1/football/meta/plans": {
      "get": {
        "tags": [
          "meta"
        ],
        "operationId": "GetPlans",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfPricingDto"
                }
              }
            }
          }
        }
      }
    },
    "/v1/football/matches/live": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetLiveMatches",
        "parameters": [
          {
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfIReadOnlyListOfMatchDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatches",
        "parameters": [
          {
            "name": "date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "league",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "tz",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfIReadOnlyListOfMatchDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatchById",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/events": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatchEvents",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchEventsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/statistics": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatchStatistics",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchStatisticsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/h2h": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatchH2h",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchH2hDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/lineups": {
      "get": {
        "tags": [
          "matches"
        ],
        "operationId": "GetMatchLineups",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchLineupsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/odds/bookmakers": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetOddsBookmakers",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfIReadOnlyListOfBookmakerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/odds": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetMatchOdds",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchOddsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/odds/exchange": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetMatchExchangeOdds",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/odds/kelly": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetMatchKellyIndex",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfKellyIndexDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/odds/hkjc": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetMatchHkjcOdds",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfHkjcOddsBoardDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/odds/{market}/{bookmaker}": {
      "get": {
        "tags": [
          "odds"
        ],
        "operationId": "GetMatchOddsMovement",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "market",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "bookmaker",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfOddsMovementDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/ai-basic": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "AI基本分析",
        "description": "Read the previously published basic AI report. Accept-Language selects stored English, simplified Chinese or traditional Chinese text. Does not generate a report; unpublished text returns 404.",
        "operationId": "GetMatchAiBasic",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchAiAnalysisDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/ai-deep": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "AI深度分析",
        "description": "Read the previously published deep AI report independently of the basic report. Does not generate a report; unpublished text returns 404.",
        "operationId": "GetMatchAiDeep",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchAiAnalysisDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/tips-distribution": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "用戶心水分布",
        "description": "Read aggregate customer tip counts. Preserves the sample threshold of more than ten tips per bet type and goal line. Empty eligible samples return an empty distribution, independently of AI publication.",
        "operationId": "GetMatchTipsDistribution",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchTipsDistributionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/handicap": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "讓球盤路分析",
        "description": "Precomputed handicap history, statistics and chart series per bookmaker for all/same-league and opening/opening-and-closing line samples. Historical names, dates and rate labels retain source formatting.",
        "operationId": "GetMatchHandicapAnalysis",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchHandicapAnalysisDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/over-under": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "入球大細盤路分析",
        "description": "Precomputed total-goals history, statistics and chart series per bookmaker, with the same four sample selections as handicap analysis.",
        "operationId": "GetMatchOverUnderAnalysis",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchOverUnderAnalysisDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    },
    "/v1/football/matches/{matchId}/analysis/corners": {
      "get": {
        "tags": [
          "analysis"
        ],
        "summary": "角球數據分析",
        "description": "Existing corner aggregates by team, home/away venue and minute. Sum minute ranges to reproduce the consumer chart; missing samples remain distinct from zero.",
        "operationId": "GetMatchCornerAnalysis",
        "parameters": [
          {
            "name": "matchId",
            "in": "path",
            "required": true,
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnvelopeOfMatchCornerAnalysisDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "ApiKey": []
          }
        ],
        "x-allowed-tiers": [
          "Plus",
          "Pro"
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ApiPlanDto": {
        "required": [
          "id",
          "planCode",
          "tier",
          "billingPeriod",
          "months",
          "price",
          "currency",
          "version"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Plan id (a specific version).",
            "format": "int32"
          },
          "planCode": {
            "type": "string",
            "description": "Stable code, e.g. TipsmeApiPlusM."
          },
          "tier": {
            "type": "string",
            "description": "Free, Plus or Pro."
          },
          "billingPeriod": {
            "type": "string",
            "description": "monthly or yearly."
          },
          "months": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Months per billing period.",
            "format": "int32"
          },
          "price": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "description": "Price per period.",
            "format": "double"
          },
          "currency": {
            "type": "string",
            "description": "ISO currency, HKD."
          },
          "version": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Plan version; prices change by inserting a new version.",
            "format": "int32"
          },
          "compareAtPrice": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "List price while the plan is on promotion.",
            "format": "double"
          },
          "discountPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Percentage off the compare-at price, when the plan is on promotion. Computed here so\nthe tag on the card can never disagree with the two prices printed beside it.",
            "format": "double"
          }
        },
        "description": "A purchasable plan version."
      },
      "BookmakerDto": {
        "required": [
          "id",
          "name",
          "nameEn",
          "isAggregate"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Permanent numeric id — part of the public contract, never renumbered.",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "The raw stored name: the exact string used in movement URLs, Redis\n    keys and the SQL `company` column. CJK and `*` are literal."
          },
          "nameEn": {
            "type": "string",
            "description": "Display name for English readers."
          },
          "isAggregate": {
            "type": "boolean",
            "description": "True for the Min/Max envelope rows, which are not real\n    bookmakers but occupy the same namespace in the stored data."
          }
        },
        "description": "One bookmaker on the public contract."
      },
      "CardCount": {
        "required": [
          "yellow",
          "red"
        ],
        "type": "object",
        "properties": {
          "yellow": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Yellow cards shown to this side.",
            "format": "int32"
          },
          "red": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Red cards shown to this side.",
            "format": "int32"
          }
        },
        "description": "Cards shown, per side. Null when upstream reported nothing."
      },
      "CompetitionRef": {
        "required": [
          "name",
          "nameOriginal"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Competition name in the requested language."
          },
          "nameOriginal": {
            "type": [
              "null",
              "string"
            ],
            "description": "Competition name as published by the source."
          }
        },
        "description": "The competition a fixture belongs to."
      },
      "CornerTeamDto": {
        "required": [
          "home",
          "away",
          "totalCorners"
        ],
        "type": "object",
        "properties": {
          "home": {
            "description": "Historical corner sample when this team played at home.",
            "$ref": "#/components/schemas/CornerVenueDto"
          },
          "away": {
            "description": "Historical corner sample when this team played away.",
            "$ref": "#/components/schemas/CornerVenueDto"
          },
          "totalCorners": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Combined corner counts at each minute across the home and away venue samples."
          }
        },
        "description": "Home/away venue splits and combined minute counts for one team."
      },
      "CornerVenueDto": {
        "required": [
          "matches",
          "firstCorners",
          "cornersFor",
          "cornersAgainst",
          "matchCornerDistributions"
        ],
        "type": "object",
        "properties": {
          "matches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Reported number of historical matches at this venue; zero and missing are distinct.",
            "format": "int32"
          },
          "firstCorners": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "First-corner counts keyed by match minute, when reported."
          },
          "cornersFor": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Corners earned by the team, aggregated by match minute."
          },
          "cornersAgainst": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            },
            "description": "Corners conceded by the team, aggregated by match minute."
          },
          "matchCornerDistributions": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "object",
              "additionalProperties": {
                "pattern": "^-?(?:0|[1-9]\\d*)$",
                "type": [
                  "integer",
                  "string"
                ],
                "format": "int32"
              }
            },
            "description": "Individual historical-match corner counts keyed by minute, without match or user identifiers."
          }
        },
        "description": "Stored corner counts by minute for a team playing at one venue. Sample size can be absent;\n    zero means a reported zero. Minute dictionaries contain aggregate counts, not percentages."
      },
      "EnvelopeOfHkjcOddsBoardDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/HkjcOddsBoardDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfIReadOnlyListOfBookmakerDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/BookmakerDto"
            }
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfIReadOnlyListOfMatchDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/MatchDto"
            }
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfIReadOnlyListOfTierLimitsDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/TierLimitsDto"
            }
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfKellyIndexDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/KellyIndexDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchAiAnalysisDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchAiAnalysisDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchCornerAnalysisDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchCornerAnalysisDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchEventsDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchEventsDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchH2hDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchH2hDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchHandicapAnalysisDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchHandicapAnalysisDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchLineupsDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchLineupsDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchOddsDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchOddsDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchOverUnderAnalysisDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchOverUnderAnalysisDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchStatisticsDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchStatisticsDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfMatchTipsDistributionDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/MatchTipsDistributionDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfOddsMovementDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/OddsMovementDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "EnvelopeOfPricingDto": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PricingDto"
              }
            ]
          },
          "meta": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PageMeta"
              }
            ]
          }
        },
        "description": "The single response shape for the `/v1` surface: collections return\n`{ \"data\": [...], \"meta\": {...} }`, single resources return `{ \"data\": {...} }`.\n`meta` is omitted entirely when null — see JsonSerializerOptions ApiJson.V1."
      },
      "GoalDistributionDto": {
        "required": [
          "timeframe",
          "homeScoredPercent",
          "homeConcededPercent",
          "awayScoredPercent",
          "awayConcededPercent"
        ],
        "type": "object",
        "properties": {
          "timeframe": {
            "type": [
              "null",
              "string"
            ],
            "description": "Slice of the match, e.g. \"0-15\"."
          },
          "homeScoredPercent": {
            "type": [
              "null",
              "string"
            ],
            "description": "Share of the home side's season goals scored in this slice."
          },
          "homeConcededPercent": {
            "type": [
              "null",
              "string"
            ],
            "description": "Share of the home side's goals conceded in this slice."
          },
          "awayScoredPercent": {
            "type": [
              "null",
              "string"
            ],
            "description": "Share of the away side's goals scored in this slice."
          },
          "awayConcededPercent": {
            "type": [
              "null",
              "string"
            ],
            "description": "Share of the away side's goals conceded in this slice."
          }
        },
        "description": "Share of goals scored and conceded within a slice of the match."
      },
      "H2hMeetingDto": {
        "required": [
          "matchId",
          "date",
          "competition",
          "homeTeam",
          "awayTeam",
          "score",
          "corners",
          "isNeutralVenue",
          "outcome"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id of the meeting.",
            "format": "int32"
          },
          "date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match date."
          },
          "competition": {
            "type": [
              "null",
              "string"
            ],
            "description": "Competition name."
          },
          "homeTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home side in that meeting."
          },
          "awayTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away side in that meeting."
          },
          "score": {
            "type": [
              "null",
              "string"
            ],
            "description": "Final score, \"home-away\"."
          },
          "corners": {
            "type": [
              "null",
              "string"
            ],
            "description": "Corner count, \"home-away\"."
          },
          "isNeutralVenue": {
            "type": "boolean",
            "description": "True when played at a neutral ground."
          },
          "outcome": {
            "description": "How the meeting finished against the common markets.",
            "$ref": "#/components/schemas/MatchOutcomeDto"
          }
        },
        "description": "A previous meeting between the two sides."
      },
      "HadQuoteDto": {
        "required": [
          "bookmaker",
          "openHome",
          "openDraw",
          "openAway",
          "closeHome",
          "closeDraw",
          "closeAway"
        ],
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bookmaker name; may carry a trailing asterisk. Use the numeric id from /odds/bookmakers in URLs."
          },
          "openHome": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening home-win price."
          },
          "openDraw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening draw price."
          },
          "openAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening away-win price."
          },
          "closeHome": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest home-win price."
          },
          "closeDraw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest draw price."
          },
          "closeAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest away-win price."
          }
        },
        "description": "Opening and closing 1X2 prices for one bookmaker."
      },
      "HandicapBookmakerDto": {
        "required": [
          "company",
          "all",
          "sameLeague",
          "sameOpeningClosing",
          "sameLeagueOpeningClosing"
        ],
        "type": "object",
        "properties": {
          "company": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored bookmaker display name."
          },
          "all": {
            "description": "Matches across competitions selected by the opening line.",
            "$ref": "#/components/schemas/HandicapSampleDto"
          },
          "sameLeague": {
            "description": "Matches from the same competition selected by the opening line.",
            "$ref": "#/components/schemas/HandicapSampleDto"
          },
          "sameOpeningClosing": {
            "description": "Matches across competitions with matching opening and closing lines.",
            "$ref": "#/components/schemas/HandicapSampleDto"
          },
          "sameLeagueOpeningClosing": {
            "description": "Matches from the same competition with matching opening and closing lines.",
            "$ref": "#/components/schemas/HandicapSampleDto"
          }
        },
        "description": "Four existing sample selections for one bookmaker: all or same league, with opening-line or opening-and-closing-line matching."
      },
      "HandicapHistoryDto": {
        "required": [
          "league",
          "matchTime",
          "home",
          "away",
          "score",
          "result",
          "opening",
          "closing"
        ],
        "type": "object",
        "properties": {
          "league": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored competition display name."
          },
          "matchTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored historical match date/time string; no timezone conversion is applied."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored home-team display name."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored away-team display name."
          },
          "score": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored historical full-time score."
          },
          "result": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored market settlement label."
          },
          "opening": {
            "description": "Stored opening market line and prices.",
            "$ref": "#/components/schemas/HandicapPriceDto"
          },
          "closing": {
            "description": "Stored closing market line and prices.",
            "$ref": "#/components/schemas/HandicapPriceDto"
          }
        },
        "description": "Historical match used in a handicap sample. Names, dates and result labels retain source formatting."
      },
      "HandicapPriceDto": {
        "required": [
          "line",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "line": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored Asian market line, retaining split-line formatting."
          },
          "home": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Odds for the home side, when reported.",
            "format": "double"
          },
          "away": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Odds for the away side, when reported.",
            "format": "double"
          }
        },
        "description": "Stored opening or closing handicap price. Missing odds are not replaced by zero."
      },
      "HandicapSampleDto": {
        "required": [
          "matches",
          "statistics",
          "winRateBySampleSize",
          "oddsDeviationDistribution"
        ],
        "type": "object",
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HandicapHistoryDto"
            },
            "description": "Historical matches in this sample."
          },
          "statistics": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Reported sample totals and rates.",
                "$ref": "#/components/schemas/HandicapStatisticsDto"
              }
            ]
          },
          "winRateBySampleSize": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            },
            "description": "Reported win rate keyed by number of recent matches."
          },
          "oddsDeviationDistribution": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            },
            "description": "Reported distribution keyed by odds-deviation threshold."
          }
        },
        "description": "One handicap sample and its precomputed chart series."
      },
      "HandicapStatisticsDto": {
        "required": [
          "openingLine",
          "totalMatches",
          "homeWins",
          "draws",
          "awayWins",
          "handicapWins",
          "handicapDraws",
          "handicapLosses",
          "winRate",
          "drawRate",
          "lossRate"
        ],
        "type": "object",
        "properties": {
          "openingLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening line used to select the historical sample."
          },
          "totalMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Reported sample size; omitted when unavailable.",
            "format": "int32"
          },
          "homeWins": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Home wins in the reported historical sample.",
            "format": "int32"
          },
          "draws": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Draws in the reported historical sample.",
            "format": "int32"
          },
          "awayWins": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Away wins in the reported historical sample.",
            "format": "int32"
          },
          "handicapWins": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches recorded as handicap wins.",
            "format": "int32"
          },
          "handicapDraws": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches recorded as handicap pushes.",
            "format": "int32"
          },
          "handicapLosses": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches recorded as handicap losses.",
            "format": "int32"
          },
          "winRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored handicap win-rate string, which may include a percent sign."
          },
          "drawRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored handicap push-rate string, which may include a percent sign."
          },
          "lossRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored handicap loss-rate string, which may include a percent sign."
          }
        },
        "description": "Precomputed handicap sample counts and stored percentage strings."
      },
      "HdpQuoteDto": {
        "required": [
          "bookmaker",
          "openLine",
          "openHome",
          "openAway",
          "closeLine",
          "closeHome",
          "closeAway"
        ],
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bookmaker name."
          },
          "openLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening handicap line, e.g. \"-0.5\" (home gives half a goal)."
          },
          "openHome": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening home price at the opening line."
          },
          "openAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening away price at the opening line."
          },
          "closeLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest handicap line."
          },
          "closeHome": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest home price."
          },
          "closeAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest away price."
          }
        },
        "description": "Opening and closing Asian handicap prices and lines for one bookmaker."
      },
      "HiloQuoteDto": {
        "required": [
          "bookmaker",
          "openLine",
          "openOver",
          "openUnder",
          "closeLine",
          "closeOver",
          "closeUnder"
        ],
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bookmaker name."
          },
          "openLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening total-goals line, e.g. \"2.5\"."
          },
          "openOver": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening over price."
          },
          "openUnder": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening under price."
          },
          "closeLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest total-goals line."
          },
          "closeOver": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest over price."
          },
          "closeUnder": {
            "type": [
              "null",
              "string"
            ],
            "description": "Latest under price."
          }
        },
        "description": "Opening and closing over/under prices and lines for one bookmaker."
      },
      "HkjcHandicapRowDto": {
        "required": [
          "homeLine",
          "awayLine",
          "home",
          "away",
          "recordedUtc"
        ],
        "type": "object",
        "properties": {
          "homeLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Line quoted on the home side, e.g. \"-1\"."
          },
          "awayLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Line quoted on the away side, e.g. \"+1\"."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home price."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away price."
          },
          "recordedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the board showed these prices.",
            "format": "date-time"
          }
        },
        "description": "A handicap variation. HKJC quotes the line per side rather than one number."
      },
      "HkjcMatchResultRowDto": {
        "required": [
          "home",
          "draw",
          "away",
          "recordedUtc"
        ],
        "type": "object",
        "properties": {
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home price."
          },
          "draw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Draw price."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away price."
          },
          "recordedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the board showed these prices.",
            "format": "date-time"
          }
        },
        "description": "A 1X2 odds variation on the HKJC board."
      },
      "HkjcOddsBoardDto": {
        "required": [
          "matchId",
          "matchResult",
          "handicap",
          "overUnder",
          "firstHalfMatchResult",
          "firstHalfOverUnder",
          "cornersOverUnder"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "matchResult": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcMatchResultRowDto"
            },
            "description": "Full-time 1X2 variations."
          },
          "handicap": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcHandicapRowDto"
            },
            "description": "Handicap variations."
          },
          "overUnder": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcOverUnderRowDto"
            },
            "description": "Full-time total-goals variations."
          },
          "firstHalfMatchResult": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcMatchResultRowDto"
            },
            "description": "First-half 1X2 variations."
          },
          "firstHalfOverUnder": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcOverUnderRowDto"
            },
            "description": "First-half total-goals variations."
          },
          "cornersOverUnder": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HkjcOverUnderRowDto"
            },
            "description": "Corner-count over/under variations."
          }
        },
        "description": "The HKJC odds board: every observed variation per market, oldest first. Sections the\nJockey Club did not price for a match are empty lists rather than absent."
      },
      "HkjcOverUnderRowDto": {
        "required": [
          "line",
          "over",
          "under",
          "recordedUtc"
        ],
        "type": "object",
        "properties": {
          "line": {
            "type": [
              "null",
              "string"
            ],
            "description": "Goals (or corners) line."
          },
          "over": {
            "type": [
              "null",
              "string"
            ],
            "description": "Over price."
          },
          "under": {
            "type": [
              "null",
              "string"
            ],
            "description": "Under price."
          },
          "recordedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the board showed these prices.",
            "format": "date-time"
          }
        },
        "description": "An over/under variation (goals or corners, per section)."
      },
      "InjuryDto": {
        "required": [
          "playerId",
          "name",
          "position",
          "reason",
          "typeCode",
          "missedMatches",
          "startUtc",
          "endUtc",
          "photoUrl"
        ],
        "type": "object",
        "properties": {
          "playerId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player identifier in the lineup data, when available."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player name."
          },
          "position": {
            "type": [
              "null",
              "string"
            ],
            "description": "Position code."
          },
          "reason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Injury or suspension description."
          },
          "typeCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Upstream absence type code.",
            "format": "int32"
          },
          "missedMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches missed so far.",
            "format": "int32"
          },
          "startUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the absence began.",
            "format": "date-time"
          },
          "endUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "Expected return, when known.",
            "format": "date-time"
          },
          "photoUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player photo."
          }
        },
        "description": "A player unavailable for this match."
      },
      "KellyIndexDto": {
        "required": [
          "matchId",
          "opening",
          "closing"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "opening": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KellyQuoteDto"
            },
            "description": "Opening quotes per bookmaker."
          },
          "closing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KellyQuoteDto"
            },
            "description": "Latest quotes per bookmaker."
          }
        },
        "description": "Kelly index (凱利指數) per bookmaker at opening and closing."
      },
      "KellyQuoteDto": {
        "required": [
          "bookmaker",
          "home",
          "draw",
          "away",
          "kellyHome",
          "kellyDraw",
          "kellyAway",
          "payout",
          "recordedUtc"
        ],
        "type": "object",
        "properties": {
          "bookmaker": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bookmaker name."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home price."
          },
          "draw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Draw price."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away price."
          },
          "kellyHome": {
            "type": [
              "null",
              "string"
            ],
            "description": "Kelly index for the home outcome; above ~1.0 suggests the bookmaker rates it more likely than the market average."
          },
          "kellyDraw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Kelly index for the draw."
          },
          "kellyAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Kelly index for the away outcome."
          },
          "payout": {
            "type": [
              "null",
              "string"
            ],
            "description": "Bookmaker payout rate (margin) for this quote."
          },
          "recordedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the quote was observed.",
            "format": "date-time"
          }
        },
        "description": "One bookmaker's 1X2 odds with the Kelly index (凱利指數) per outcome."
      },
      "LeagueRecordDto": {
        "required": [
          "split",
          "rank",
          "played",
          "won",
          "drawn",
          "lost",
          "goalsFor",
          "goalsAgainst",
          "goalDifference",
          "points",
          "winRate"
        ],
        "type": "object",
        "properties": {
          "split": {
            "type": [
              "null",
              "string"
            ],
            "description": "overall, home or away."
          },
          "rank": {
            "type": [
              "null",
              "string"
            ],
            "description": "League position."
          },
          "played": {
            "type": [
              "null",
              "string"
            ],
            "description": "Matches played."
          },
          "won": {
            "type": [
              "null",
              "string"
            ],
            "description": "Wins."
          },
          "drawn": {
            "type": [
              "null",
              "string"
            ],
            "description": "Draws."
          },
          "lost": {
            "type": [
              "null",
              "string"
            ],
            "description": "Losses."
          },
          "goalsFor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Goals scored."
          },
          "goalsAgainst": {
            "type": [
              "null",
              "string"
            ],
            "description": "Goals conceded."
          },
          "goalDifference": {
            "type": [
              "null",
              "string"
            ],
            "description": "Goal difference."
          },
          "points": {
            "type": [
              "null",
              "string"
            ],
            "description": "Points."
          },
          "winRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Win rate as a percentage."
          }
        },
        "description": "A standings slice. `Split` distinguishes overall from home-only and away-only\nrecords, as reported upstream."
      },
      "LineupAbsenceDto": {
        "required": [
          "playerId",
          "name",
          "position",
          "reason",
          "missedMatches",
          "startUtc",
          "endUtc",
          "photoUrl"
        ],
        "type": "object",
        "properties": {
          "playerId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player identifier in the lineup data, when available."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player name as reported."
          },
          "position": {
            "type": [
              "null",
              "string"
            ],
            "description": "Position code, when available."
          },
          "reason": {
            "type": [
              "null",
              "string"
            ],
            "description": "Reported injury, suspension or other absence description."
          },
          "missedMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches missed so far, when reported.",
            "format": "int32"
          },
          "startUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When the absence began.",
            "format": "date-time"
          },
          "endUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "Expected return, when known.",
            "format": "date-time"
          },
          "photoUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player photo."
          }
        },
        "description": "A player unavailable for the match, with reported absence details."
      },
      "LineupEventDto": {
        "required": [
          "type",
          "minute",
          "stoppageTime",
          "score",
          "player",
          "assists",
          "substitution"
        ],
        "type": "object",
        "properties": {
          "type": {
            "description": "Event kind; unknown when no supported mapping is available.",
            "$ref": "#/components/schemas/LineupEventType"
          },
          "minute": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Match minute.",
            "format": "int32"
          },
          "stoppageTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Additional minute in stoppage time, when reported.",
            "format": "int32"
          },
          "score": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Score after the event, when reported.",
                "$ref": "#/components/schemas/LineupEventScoreDto"
              }
            ]
          },
          "player": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The player involved, when reported.",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "assists": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlayerRefDto"
            },
            "description": "Assisting players in reported order; empty when none are reported."
          },
          "substitution": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Players coming on and going off, when reported.",
                "$ref": "#/components/schemas/LineupSubstitutionDto"
              }
            ]
          }
        },
        "description": "A normalized event involving a match squad player."
      },
      "LineupEventScoreDto": {
        "required": [
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "home": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Home goals after the event, when reported.",
            "format": "int32"
          },
          "away": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Away goals after the event, when reported.",
            "format": "int32"
          }
        },
        "description": "Score reported with a lineup event."
      },
      "LineupEventType": {
        "enum": [
          "unknown",
          "goal",
          "yellowCard",
          "redCard",
          "injury",
          "penalty",
          "substitution",
          "secondYellowCard",
          "missedPenalty"
        ],
        "description": "Normalized lineup event kind. Unknown preserves an event whose kind cannot be identified."
      },
      "LineupIncidentDto": {
        "required": [
          "typeCode",
          "minute",
          "stoppageTime",
          "homeScore",
          "awayScore",
          "player",
          "assist1",
          "assist2",
          "playerIn",
          "playerOut"
        ],
        "type": "object",
        "properties": {
          "typeCode": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Upstream incident type code (goal, own goal, yellow, red, substitution…).",
            "format": "int32"
          },
          "minute": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Match minute.",
            "format": "int32"
          },
          "stoppageTime": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Stoppage minute when the incident fell in added time.",
            "format": "int32"
          },
          "homeScore": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Home score after the incident (goals only).",
            "format": "int32"
          },
          "awayScore": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Away score after the incident (goals only).",
            "format": "int32"
          },
          "player": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The player involved.",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "assist1": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "First assist (goals).",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "assist2": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Second assist (goals).",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "playerIn": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Player coming on (substitutions).",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "playerOut": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Player going off (substitutions).",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          }
        },
        "description": "Legacy incident details retained for compatibility. Use LineupEventDto\nfor normalized event names and grouped details."
      },
      "LineupPlayerDto": {
        "required": [
          "id",
          "name",
          "shirtNumber",
          "position",
          "isStarter",
          "isCaptain",
          "rating",
          "pitch",
          "photoUrl",
          "incidents"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player identifier in the lineup data, when available."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player name as available in the match lineup."
          },
          "shirtNumber": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Shirt number.",
            "format": "int32"
          },
          "position": {
            "type": [
              "null",
              "string"
            ],
            "description": "Position code, e.g. \"GK\", \"DF\", \"MF\", \"FW\"."
          },
          "isStarter": {
            "type": "boolean",
            "description": "True for the starting eleven."
          },
          "isCaptain": {
            "type": "boolean",
            "description": "True for the captain."
          },
          "rating": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match rating out of 10, when available."
          },
          "pitch": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Position on the pitch for the starting eleven; null for the bench.",
                "$ref": "#/components/schemas/PitchPositionDto"
              }
            ]
          },
          "photoUrl": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player photo."
          },
          "incidents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineupIncidentDto"
            },
            "description": "Deprecated: use events for normalized event names and grouped details. Retained for existing clients."
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineupEventDto"
            },
            "description": "Normalized goals, cards, injuries and substitutions involving this player."
          }
        },
        "description": "One player in a match squad, with position, rating and incidents."
      },
      "LineupSubstitutionDto": {
        "required": [
          "in",
          "out"
        ],
        "type": "object",
        "properties": {
          "in": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Player coming on, when reported.",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          },
          "out": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Player going off, when reported.",
                "$ref": "#/components/schemas/PlayerRefDto"
              }
            ]
          }
        },
        "description": "Players involved in a substitution."
      },
      "MatchAiAnalysisDto": {
        "required": [
          "matchId",
          "kind",
          "language",
          "text"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric Tipsme match id.",
            "format": "int32"
          },
          "kind": {
            "type": "string",
            "description": "basic or deep."
          },
          "language": {
            "type": "string",
            "description": "Language of the stored text: en, zh-CN or zh-HK."
          },
          "text": {
            "type": "string",
            "description": "Stored report text, which may contain Markdown."
          }
        },
        "description": "Previously published AI report. Reading never triggers generation."
      },
      "MatchCornerAnalysisDto": {
        "required": [
          "matchId",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric Tipsme match id; the same id accepted by the match endpoints.",
            "format": "int32"
          },
          "home": {
            "description": "Corner analysis for the current home team.",
            "$ref": "#/components/schemas/CornerTeamDto"
          },
          "away": {
            "description": "Corner analysis for the current away team.",
            "$ref": "#/components/schemas/CornerTeamDto"
          }
        },
        "description": "Existing corner aggregates for the two teams. Clients may sum minute ranges to reproduce the consumer chart."
      },
      "MatchDto": {
        "required": [
          "id",
          "kickoffUtc",
          "competition",
          "home",
          "away",
          "status",
          "minute",
          "additionalTime",
          "score",
          "homeCards",
          "awayCards",
          "corners",
          "isNeutralVenue",
          "isCup",
          "isBracket",
          "isHkjc"
        ],
        "type": "object",
        "properties": {
          "id": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id. Use it on every /matches/{matchId}/… endpoint.",
            "format": "int32"
          },
          "kickoffUtc": {
            "type": "string",
            "description": "Scheduled kickoff, ISO-8601 UTC.",
            "format": "date-time"
          },
          "competition": {
            "description": "Competition name(s).",
            "$ref": "#/components/schemas/CompetitionRef"
          },
          "home": {
            "description": "Home side.",
            "$ref": "#/components/schemas/TeamRef"
          },
          "away": {
            "description": "Away side.",
            "$ref": "#/components/schemas/TeamRef"
          },
          "status": {
            "description": "scheduled, live, finished, postponed or cancelled — normalised, never a localised string.",
            "$ref": "#/components/schemas/MatchState"
          },
          "minute": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match minute while live, e.g. \"63\" or \"45+2\"."
          },
          "additionalTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stoppage time announced for the current half, in minutes."
          },
          "score": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Scores per phase; null before kickoff.",
                "$ref": "#/components/schemas/ScoreDto"
              }
            ]
          },
          "homeCards": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Cards shown to the home side.",
                "$ref": "#/components/schemas/CardCount"
              }
            ]
          },
          "awayCards": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Cards shown to the away side.",
                "$ref": "#/components/schemas/CardCount"
              }
            ]
          },
          "corners": {
            "type": [
              "null",
              "string"
            ],
            "description": "Corner count, \"home-away\"."
          },
          "isNeutralVenue": {
            "type": "boolean",
            "description": "True when played at a neutral ground."
          },
          "isCup": {
            "type": "boolean",
            "description": "True for cup competitions."
          },
          "isBracket": {
            "type": "boolean",
            "description": "True when the fixture belongs to a knockout bracket."
          },
          "isHkjc": {
            "type": "boolean",
            "description": "True when the Hong Kong Jockey Club offers this fixture; HKJC odds exist only for these."
          },
          "homeLogo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home team PNG URL on assets.tipsme.hk, built from the original team name. Omitted when the original name is unavailable; the image may be unavailable."
          },
          "awayLogo": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away team PNG URL on assets.tipsme.hk, built from the original team name. Omitted when the original name is unavailable; the image may be unavailable."
          }
        },
        "description": "A match identified by its numeric Tipsme match id. Source identifiers are resolved\ninternally. User state and presentation-only data are omitted."
      },
      "MatchEventDto": {
        "required": [
          "minute",
          "homeType",
          "homeDetail",
          "awayType",
          "awayDetail"
        ],
        "type": "object",
        "properties": {
          "minute": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match minute of the event."
          },
          "homeType": {
            "type": [
              "null",
              "string"
            ],
            "description": "Event type for the home side (goal, yellow card, substitution…), when it was theirs."
          },
          "homeDetail": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player and detail text for the home event."
          },
          "awayType": {
            "type": [
              "null",
              "string"
            ],
            "description": "Event type for the away side, when it was theirs."
          },
          "awayDetail": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player and detail text for the away event."
          }
        },
        "description": "A timed event, expressed per side so a caller can attribute it without parsing."
      },
      "MatchEventsDto": {
        "required": [
          "matchId",
          "events",
          "corners",
          "technicalStats",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MatchEventDto"
            },
            "description": "Goals, cards and substitutions in time order."
          },
          "corners": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimedTallyDto"
            },
            "description": "Running corner count over time."
          },
          "technicalStats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimedTallyDto"
            },
            "description": "Running technical tallies (shots, attacks…) over time."
          },
          "home": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Home lineup, when published.",
                "$ref": "#/components/schemas/MatchLineupDto"
              }
            ]
          },
          "away": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Away lineup, when published.",
                "$ref": "#/components/schemas/MatchLineupDto"
              }
            ]
          }
        },
        "description": "The minute-by-minute timeline plus in-play tallies and simple lineups."
      },
      "MatchH2hDto": {
        "required": [
          "matchId",
          "meetings",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "meetings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/H2hMeetingDto"
            },
            "description": "Previous meetings between the two sides, newest first."
          },
          "home": {
            "description": "Home side context.",
            "$ref": "#/components/schemas/TeamContextDto"
          },
          "away": {
            "description": "Away side context.",
            "$ref": "#/components/schemas/TeamContextDto"
          }
        },
        "description": "Head-to-head history plus each side's form and league context."
      },
      "MatchHandicapAnalysisDto": {
        "required": [
          "matchId",
          "bookmakers"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric Tipsme match id; the same id accepted by the match endpoints.",
            "format": "int32"
          },
          "bookmakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HandicapBookmakerDto"
            },
            "description": "Bookmakers with a published dataset; source coverage may differ between markets."
          }
        }
      },
      "MatchLineupDto": {
        "required": [
          "formation",
          "starters",
          "bench"
        ],
        "type": "object",
        "properties": {
          "formation": {
            "type": [
              "null",
              "string"
            ],
            "description": "Formation string, e.g. \"4-2-3-1\"."
          },
          "starters": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Starting eleven, as names."
          },
          "bench": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Substitutes, as names."
          }
        },
        "description": "Starting eleven, bench and formation, as reported in the match feed."
      },
      "MatchLineupsDto": {
        "required": [
          "matchId",
          "confirmed",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "confirmed": {
            "type": "boolean",
            "description": "True once the official lineups are published; false for predicted ones."
          },
          "home": {
            "description": "Home squad.",
            "$ref": "#/components/schemas/TeamSquadDto"
          },
          "away": {
            "description": "Away squad.",
            "$ref": "#/components/schemas/TeamSquadDto"
          }
        },
        "description": "Structured lineups for both sides. Appears shortly before kickoff; empty squads mean \"not published yet\"."
      },
      "MatchOddsDto": {
        "required": [
          "matchId",
          "lastUpdatedUtc",
          "matchResult",
          "asianHandicap",
          "overUnder"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "lastUpdatedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When any price on this match last changed.",
            "format": "date-time"
          },
          "matchResult": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HadQuoteDto"
            },
            "description": "1X2 (home / draw / away)."
          },
          "asianHandicap": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HdpQuoteDto"
            },
            "description": "Asian handicap lines and prices."
          },
          "overUnder": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HiloQuoteDto"
            },
            "description": "Total-goals over/under lines and prices."
          }
        },
        "description": "Opening and closing prices from every covered bookmaker, in the three Asian markets."
      },
      "MatchOutcomeDto": {
        "required": [
          "result",
          "handicap",
          "overUnder",
          "halfTimeFullTime"
        ],
        "type": "object",
        "properties": {
          "result": {
            "type": [
              "null",
              "string"
            ],
            "description": "Win / draw / loss from the home side's view."
          },
          "handicap": {
            "type": [
              "null",
              "string"
            ],
            "description": "Whether the home side covered the Asian handicap."
          },
          "overUnder": {
            "type": [
              "null",
              "string"
            ],
            "description": "Whether the match went over or under the goals line."
          },
          "halfTimeFullTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Half-time / full-time result pair."
          }
        },
        "description": "How a match finished, relative to the common Asian markets."
      },
      "MatchOverUnderAnalysisDto": {
        "required": [
          "matchId",
          "bookmakers"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric Tipsme match id; the same id accepted by the match endpoints.",
            "format": "int32"
          },
          "bookmakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OverUnderBookmakerDto"
            },
            "description": "Bookmakers with a published dataset; source coverage may differ between markets."
          }
        }
      },
      "MatchState": {
        "type": "integer",
        "description": "Normalised match state, derived from the upstream live-time strings."
      },
      "MatchStatisticsDto": {
        "required": [
          "matchId",
          "goalDistribution",
          "metrics"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "goalDistribution": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GoalDistributionDto"
            },
            "description": "Goals scored / conceded per 15-minute slice."
          },
          "metrics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamMetricDto"
            },
            "description": "Season-average metrics, home versus away."
          }
        },
        "description": "Pre-match statistical context: when each side scores and concedes, and season averages side by side."
      },
      "MatchTipsDistributionDto": {
        "required": [
          "matchId",
          "distribution"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Numeric Tipsme match id; the same id accepted by the match endpoints.",
            "format": "int32"
          },
          "distribution": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TipsDistributionRowDto"
            },
            "description": "Eligible grouped counts; empty when no sample exceeds the reporting threshold."
          }
        },
        "description": "Groups preserve the consumer sample threshold: more than ten tips per bet type and goal line.\n    An empty list means no eligible sample is available; it does not depend on an AI report."
      },
      "OddsMarket": {
        "type": "integer",
        "description": "The three markets this API publishes."
      },
      "OddsMovementDto": {
        "required": [
          "matchId",
          "market",
          "bookmaker",
          "opening",
          "history"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "market": {
            "description": "had, hdp or hilo.",
            "$ref": "#/components/schemas/OddsMarket"
          },
          "bookmaker": {
            "type": "string",
            "description": "Bookmaker the series belongs to."
          },
          "opening": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The first observed price.",
                "$ref": "#/components/schemas/OddsPointDto"
              }
            ]
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OddsPointDto"
            },
            "description": "Every observation after the opening, in time order."
          }
        },
        "description": "The full price history for one bookmaker in one market — every observed change, oldest first."
      },
      "OddsPointDto": {
        "required": [
          "recordedUtc",
          "line",
          "home",
          "draw",
          "away",
          "over",
          "under"
        ],
        "type": "object",
        "properties": {
          "recordedUtc": {
            "type": [
              "null",
              "string"
            ],
            "description": "When this price was observed.",
            "format": "date-time"
          },
          "line": {
            "type": [
              "null",
              "string"
            ],
            "description": "Handicap or total line (hdp / hilo only)."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home price (had / hdp)."
          },
          "draw": {
            "type": [
              "null",
              "string"
            ],
            "description": "Draw price (had only)."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away price (had / hdp)."
          },
          "over": {
            "type": [
              "null",
              "string"
            ],
            "description": "Over price (hilo only)."
          },
          "under": {
            "type": [
              "null",
              "string"
            ],
            "description": "Under price (hilo only)."
          }
        },
        "description": "One observation in a movement series. Only the members meaningful to the requested\nmarket are populated — `Draw` for 1X2, `Line` plus over/under for the others."
      },
      "OverUnderBookmakerDto": {
        "required": [
          "company",
          "all",
          "sameLeague",
          "sameOpeningClosing",
          "sameLeagueOpeningClosing"
        ],
        "type": "object",
        "properties": {
          "company": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored bookmaker display name."
          },
          "all": {
            "description": "Matches across competitions selected by the opening line.",
            "$ref": "#/components/schemas/OverUnderSampleDto"
          },
          "sameLeague": {
            "description": "Matches from the same competition selected by the opening line.",
            "$ref": "#/components/schemas/OverUnderSampleDto"
          },
          "sameOpeningClosing": {
            "description": "Matches across competitions with matching opening and closing lines.",
            "$ref": "#/components/schemas/OverUnderSampleDto"
          },
          "sameLeagueOpeningClosing": {
            "description": "Matches from the same competition with matching opening and closing lines.",
            "$ref": "#/components/schemas/OverUnderSampleDto"
          }
        },
        "description": "Four existing goals sample selections for one bookmaker."
      },
      "OverUnderHistoryDto": {
        "required": [
          "league",
          "matchTime",
          "home",
          "away",
          "score",
          "result",
          "opening",
          "closing"
        ],
        "type": "object",
        "properties": {
          "league": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored competition display name."
          },
          "matchTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored historical match date/time string; no timezone conversion is applied."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored home-team display name."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored away-team display name."
          },
          "score": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored historical full-time score."
          },
          "result": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored market settlement label."
          },
          "opening": {
            "description": "Stored opening market line and prices.",
            "$ref": "#/components/schemas/OverUnderPriceDto"
          },
          "closing": {
            "description": "Stored closing market line and prices.",
            "$ref": "#/components/schemas/OverUnderPriceDto"
          }
        },
        "description": "Historical match used in a goals sample. Names, dates and result labels retain source formatting."
      },
      "OverUnderPriceDto": {
        "required": [
          "line",
          "over",
          "under"
        ],
        "type": "object",
        "properties": {
          "line": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored Asian market line, retaining split-line formatting."
          },
          "over": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Odds for the over outcome, when reported.",
            "format": "double"
          },
          "under": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Odds for the under outcome, when reported.",
            "format": "double"
          }
        },
        "description": "Stored opening or closing total-goals price."
      },
      "OverUnderSampleDto": {
        "required": [
          "matches",
          "statistics",
          "winRateBySampleSize",
          "oddsDeviationDistribution"
        ],
        "type": "object",
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OverUnderHistoryDto"
            },
            "description": "Historical matches in this sample."
          },
          "statistics": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Precomputed sample counts and rates, when reported.",
                "$ref": "#/components/schemas/OverUnderStatisticsDto"
              }
            ]
          },
          "winRateBySampleSize": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            },
            "description": "Reported win-rate chart series keyed by number of recent matches."
          },
          "oddsDeviationDistribution": {
            "type": [
              "null",
              "object"
            ],
            "additionalProperties": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            },
            "description": "Reported chart distribution keyed by opening/closing odds-deviation threshold."
          }
        },
        "description": "One goals sample and its precomputed chart series."
      },
      "OverUnderStatisticsDto": {
        "required": [
          "openingLine",
          "totalMatches",
          "overMatches",
          "underMatches",
          "overRate",
          "underRate"
        ],
        "type": "object",
        "properties": {
          "openingLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Opening line used to select the historical sample."
          },
          "totalMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Reported sample size; omitted when unavailable.",
            "format": "int32"
          },
          "overMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches recorded as over the total-goals line.",
            "format": "int32"
          },
          "underMatches": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "description": "Matches recorded as under the total-goals line.",
            "format": "int32"
          },
          "overRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored over-result rate string, which may include a percent sign."
          },
          "underRate": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored under-result rate string, which may include a percent sign."
          }
        },
        "description": "Precomputed total-goals sample counts and stored percentage strings."
      },
      "PageMeta": {
        "required": [
          "page",
          "pageSize",
          "total",
          "totalPages"
        ],
        "type": "object",
        "properties": {
          "page": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "1-based page number.",
            "format": "int32"
          },
          "pageSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Items per page (default 25, max 100).",
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Total items across all pages.",
            "format": "int32"
          },
          "totalPages": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Total pages.",
            "format": "int32"
          }
        },
        "description": "Pagination for collection responses."
      },
      "PitchPositionDto": {
        "required": [
          "x",
          "y"
        ],
        "type": "object",
        "properties": {
          "x": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Horizontal position, 0 (own goal line) to 100.",
            "format": "int32"
          },
          "y": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Vertical position, 0 (left touchline) to 100.",
            "format": "int32"
          }
        },
        "description": "Position on the pitch, 0-100 on each axis. Null for players who did not appear."
      },
      "PlayerRefDto": {
        "required": [
          "id",
          "name"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player identifier in the lineup data, when available."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player name."
          }
        },
        "description": "A player reference."
      },
      "PricingDto": {
        "required": [
          "currency",
          "tiers",
          "propagationSeconds"
        ],
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "description": "ISO currency for every price."
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingTierDto"
            },
            "description": "One entry per tier, Free first."
          },
          "propagationSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "How long a plan change takes to reach enforcement.",
            "format": "int32"
          },
          "recommendedTier": {
            "type": "string",
            "description": "The tier the pricing page highlights.",
            "default": "Plus"
          },
          "freeMatchesDailyQuota": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "The Free tier's fixture-list allowance. Deprecated: each tier's own value is in `tiers[].limits.freeMatchesDailyQuota`; this stays for clients built before the allowance was per tier.",
            "format": "int32",
            "default": 0
          }
        },
        "description": "The plan catalogue as the pricing page renders it."
      },
      "PricingTierDto": {
        "required": [
          "tier",
          "limits",
          "monthly",
          "yearly",
          "yearlySavingPercent"
        ],
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "description": "Tier name."
          },
          "limits": {
            "description": "What the tier allows.",
            "$ref": "#/components/schemas/TierLimitsDto"
          },
          "monthly": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Monthly plan, null for Free.",
                "$ref": "#/components/schemas/ApiPlanDto"
              }
            ]
          },
          "yearly": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "Yearly plan, null for Free.",
                "$ref": "#/components/schemas/ApiPlanDto"
              }
            ]
          },
          "yearlySavingPercent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Saving of the yearly plan versus twelve monthly payments.",
            "format": "double"
          },
          "yearlyMonthlyEquivalent": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "description": "Yearly price divided by twelve.",
            "format": "double"
          }
        },
        "description": "One tier as a purchase decision: what it costs monthly and yearly, and what it allows."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ScoreDto": {
        "required": [
          "current",
          "halfTime",
          "extraTime",
          "penalty"
        ],
        "type": "object",
        "properties": {
          "current": {
            "type": [
              "null",
              "string"
            ],
            "description": "Current (or final) score, \"home-away\"."
          },
          "halfTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Score at half time."
          },
          "extraTime": {
            "type": [
              "null",
              "string"
            ],
            "description": "Score after extra time, when played."
          },
          "penalty": {
            "type": [
              "null",
              "string"
            ],
            "description": "Penalty shoot-out score, when one took place."
          }
        },
        "description": "Scores as reported upstream, in `\"home-away\"` form. Null members mean the phase\ndid not occur — most matches have no extra time or penalties."
      },
      "SquadRatingDto": {
        "required": [
          "shirtNumber",
          "name",
          "position",
          "seasonRating"
        ],
        "type": "object",
        "properties": {
          "shirtNumber": {
            "type": [
              "null",
              "string"
            ],
            "description": "Shirt number."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Player name."
          },
          "position": {
            "type": [
              "null",
              "string"
            ],
            "description": "Position code."
          },
          "seasonRating": {
            "type": [
              "null",
              "string"
            ],
            "description": "Season rating, a different measure from the per-match rating."
          }
        },
        "description": "A squad member as available in the supplementary squad data, with a\nseason ranking, which is a different measure from the per-match rating on\nLineupPlayerDto."
      },
      "TeamContextDto": {
        "required": [
          "recentMatches",
          "leagueRecords",
          "upcoming"
        ],
        "type": "object",
        "properties": {
          "recentMatches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamFormMatchDto"
            },
            "description": "Most recent results, newest first."
          },
          "leagueRecords": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeagueRecordDto"
            },
            "description": "Standings split by overall / home / away."
          },
          "upcoming": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpcomingFixtureDto"
            },
            "description": "Next fixtures."
          }
        },
        "description": "Recent results, league records and upcoming fixtures for one side."
      },
      "TeamFormMatchDto": {
        "required": [
          "matchId",
          "date",
          "competition",
          "homeTeam",
          "awayTeam",
          "score",
          "halfTimeScore",
          "homeCorners",
          "awayCorners",
          "homeRedCards",
          "awayRedCards",
          "isNeutralVenue",
          "outcome"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Tipsme match id.",
            "format": "int32"
          },
          "date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match date."
          },
          "competition": {
            "type": [
              "null",
              "string"
            ],
            "description": "Competition name."
          },
          "homeTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home side."
          },
          "awayTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away side."
          },
          "score": {
            "type": [
              "null",
              "string"
            ],
            "description": "Final score."
          },
          "halfTimeScore": {
            "type": [
              "null",
              "string"
            ],
            "description": "Half-time score."
          },
          "homeCorners": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home corners."
          },
          "awayCorners": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away corners."
          },
          "homeRedCards": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home red cards."
          },
          "awayRedCards": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away red cards."
          },
          "isNeutralVenue": {
            "type": "boolean",
            "description": "True when played at a neutral ground."
          },
          "outcome": {
            "description": "Result against the common markets.",
            "$ref": "#/components/schemas/MatchOutcomeDto"
          }
        },
        "description": "One of a team's recent results."
      },
      "TeamMetricDto": {
        "required": [
          "metric",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "metric": {
            "type": [
              "null",
              "string"
            ],
            "description": "Metric name, e.g. \"Shots on target\"."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home side season average."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away side season average."
          }
        },
        "description": "A named season-average metric, home versus away."
      },
      "TeamRef": {
        "required": [
          "name",
          "nameOriginal",
          "ranking"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Team name in the requested language (Accept-Language), falling back to the original."
          },
          "nameOriginal": {
            "type": [
              "null",
              "string"
            ],
            "description": "Team name as published by the source."
          },
          "ranking": {
            "type": [
              "null",
              "string"
            ],
            "description": "League position at kickoff, when known."
          }
        },
        "description": "A side of a fixture."
      },
      "TeamSquadDto": {
        "required": [
          "formation",
          "coachId",
          "players",
          "injuries",
          "squadRatings",
          "recentTeamRatings"
        ],
        "type": "object",
        "properties": {
          "formation": {
            "type": [
              "null",
              "string"
            ],
            "description": "Formation string, e.g. \"4-3-3\"."
          },
          "coachId": {
            "type": [
              "null",
              "string"
            ],
            "description": "Coach identifier in the lineup data, when available."
          },
          "players": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineupPlayerDto"
            },
            "description": "Starting eleven and bench."
          },
          "injuries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InjuryDto"
            },
            "description": "Deprecated: use absences for unavailable players. Retained for existing clients."
          },
          "squadRatings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SquadRatingDto"
            },
            "description": "Season ratings per squad member."
          },
          "recentTeamRatings": {
            "type": "array",
            "items": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            },
            "description": "Team rating in recent matches, most recent first."
          },
          "absences": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineupAbsenceDto"
            },
            "description": "Unavailable players with reported reasons and absence dates."
          }
        },
        "description": "One side's squad for the match."
      },
      "TierFeaturesDto": {
        "required": [
          "analysis"
        ],
        "type": "object",
        "properties": {
          "analysis": {
            "type": "boolean",
            "description": "Whether this tier may call the Analysis endpoints."
          }
        },
        "description": "Features available to a developer subscription tier."
      },
      "TierLimitsDto": {
        "required": [
          "tier",
          "dailyQuota",
          "ratePerMinute",
          "maxKeys",
          "maxAllowlistEntriesPerKey",
          "freeMatchesDailyQuota"
        ],
        "type": "object",
        "properties": {
          "tier": {
            "type": "string",
            "description": "Tier name."
          },
          "dailyQuota": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Base requests per account per Hong Kong calendar day.",
            "format": "int32"
          },
          "ratePerMinute": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Requests per minute per API key; applies to base and bonus requests.",
            "format": "int32"
          },
          "maxKeys": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "One unrevoked API key per consumer; expired keys count until revoked.",
            "format": "int32"
          },
          "maxAllowlistEntriesPerKey": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "IP allowlist entries per key.",
            "format": "int32"
          },
          "freeMatchesDailyQuota": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Extra free GET /v1/football/matches requests per consumer per Hong Kong day for this tier, used before the base allowance.",
            "format": "int32"
          },
          "features": {
            "description": "Feature entitlements enforced for this tier.",
            "$ref": "#/components/schemas/TierFeaturesDto"
          }
        },
        "description": "The limits attached to a tier, as the gate actually resolves them."
      },
      "TimedTallyDto": {
        "required": [
          "minute",
          "home",
          "away"
        ],
        "type": "object",
        "properties": {
          "minute": {
            "type": [
              "null",
              "string"
            ],
            "description": "Match minute of the reading."
          },
          "home": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home tally at that minute."
          },
          "away": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away tally at that minute."
          }
        },
        "description": "A running home/away tally at a point in the match — corners, shots, and similar."
      },
      "TipsDistributionRowDto": {
        "required": [
          "betType",
          "predictResult",
          "handicapLine",
          "goalLine",
          "count"
        ],
        "type": "object",
        "properties": {
          "betType": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored market label, such as 讓球 or 入球大細."
          },
          "predictResult": {
            "type": [
              "null",
              "string"
            ],
            "description": "Stored predicted outcome label."
          },
          "handicapLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Handicap line of this tip group; omitted when not applicable."
          },
          "goalLine": {
            "type": [
              "null",
              "string"
            ],
            "description": "Goal-total line of this tip group; omitted when not applicable."
          },
          "count": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "description": "Number of Tipsme tips in this outcome and line group.",
            "format": "int32"
          }
        },
        "description": "Aggregate customer tips; individual authors and tips are not included."
      },
      "UpcomingFixtureDto": {
        "required": [
          "date",
          "daysAway",
          "competition",
          "homeTeam",
          "awayTeam"
        ],
        "type": "object",
        "properties": {
          "date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fixture date."
          },
          "daysAway": {
            "type": [
              "null",
              "string"
            ],
            "description": "Days until the fixture."
          },
          "competition": {
            "type": [
              "null",
              "string"
            ],
            "description": "Competition name."
          },
          "homeTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Home side."
          },
          "awayTeam": {
            "type": [
              "null",
              "string"
            ],
            "description": "Away side."
          }
        },
        "description": "An upcoming fixture, with the two sides as separate members rather than the\npre-joined \"{home} VS {away}\" string the upstream payload carries."
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "http",
        "description": "Send your API key as 'Authorization: Bearer <key>'. 'X-Api-Key: <key>' is also accepted.",
        "scheme": "bearer",
        "bearerFormat": "tsm_live_… or tsm_test_…"
      }
    }
  },
  "tags": [
    {
      "name": "meta"
    },
    {
      "name": "matches"
    },
    {
      "name": "odds"
    },
    {
      "name": "analysis"
    }
  ]
}
