openapi: 3.1.0
info:
  title: StatBasket Data API
  version: 1.0.0
  description: Read-only commercial API for StatBasket match and statistics data.
servers:
  - url: https://api.statbasket.it/v1/data
security:
  - bearerApiKey: []
components:
  securitySchemes:
    bearerApiKey:
      type: http
      scheme: bearer
      bearerFormat: StatBasket API key
  schemas:
    ApiError:
      type: object
      properties:
        error:
          type: object
          required: [code, message, request_id]
          properties:
            code: { type: string }
            message: { type: string }
            request_id: { type: [string, 'null'] }
paths:
  /:
    get:
      security: []
      summary: API information
      responses:
        '200': { description: Service information }
  /health:
    get:
      security: []
      summary: Health check
      responses:
        '200': { description: Service available }
        '503': { description: Service unavailable }
  /matches:
    get:
      summary: List matches
      parameters:
        - { in: query, name: competition_id, schema: { type: integer } }
        - { in: query, name: season_id, schema: { type: integer } }
        - { in: query, name: group_id, schema: { type: integer } }
        - { in: query, name: status, schema: { type: string } }
        - { in: query, name: limit, schema: { type: integer, default: 100, maximum: 500 } }
        - { in: query, name: offset, schema: { type: integer, default: 0 } }
      responses:
        '200': { description: Match list }
        '401': { description: Missing or invalid API key }
        '403': { description: Insufficient scope }
  /matches/{id}/live:
    get:
      summary: Live score and match state
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Live match }
        '404': { description: Match not found }
  /matches/{id}/boxscore:
    get:
      summary: Full match boxscore
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Team and player boxscore }
  /matches/{id}/play-by-play:
    get:
      summary: Ordered play by play
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
        - { in: query, name: after_seq, schema: { type: integer, default: 0 } }
        - { in: query, name: limit, schema: { type: integer, default: 250, maximum: 1000 } }
      responses:
        '200': { description: Play by play page }
  /matches/{id}/periods:
    get:
      summary: Statistics by period
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Period and total statistics }
  /matches/{id}/shots:
    get:
      summary: FIBA LiveStats shot map
      description: Requires the shots:read scope.
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Ordered shots with coordinates and player data }
        '403': { description: Insufficient scope or competition not allowed }
  /matches/{id}/lineups:
    get:
      summary: Rosters, starters, current lineups and lineup stints
      description: Requires the lineups:read scope.
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Lineup data and stints }
        '403': { description: Insufficient scope or competition not allowed }
  /matches/{id}/commentary:
    get:
      summary: Latest generated AI commentary
      description: Read-only. Requires ai:read; generation remains administrator-only.
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200': { description: Latest commentary or available=false }
        '403': { description: Insufficient scope or competition not allowed }
  /matches/{id}/boxscore.pdf:
    get:
      summary: Boxscore PDF
      description: Streams the FIBA or LNP boxscore PDF. Requires pdf:read.
      parameters:
        - { in: path, name: id, required: true, schema: { type: integer } }
      responses:
        '200':
          description: PDF boxscore
          content:
            application/pdf: {}
        '403': { description: Insufficient scope or competition not allowed }
        '502': { description: PDF temporarily unavailable }
  /standings:
    get:
      summary: Competition standings
      parameters:
        - { in: query, name: competition_id, schema: { type: integer } }
        - { in: query, name: season_id, schema: { type: integer } }
      responses:
        '200': { description: Standings }
