{
  "openapi": "3.1.0",
  "info": {
    "title": "NBA AI Insights feed API — integration view",
    "version": "0.2.0",
    "description": "NBA-typed integration view of the public generic external fixture content feed API (openapi.json). It does not define a second API. Every read is public and read-only: no authentication, no rate limit. The feed route serves the bundled sample fixtures and the deployment's public live feeds. Every response carries Access-Control-Allow-Origin: * and Access-Control-Expose-Headers: ETag; HEAD returns the GET headers without a body and OPTIONS answers CORS preflight with 204. The Worker serves this document at /v1/openapi.json and its two referenced schemas beside it, so the relative references resolve."
  },
  "security": [],
  "paths": {
    "/v1/fixtures": {
      "get": {
        "operationId": "listNbaAiInsightsFixtures",
        "summary": "List the sample fixtures and the feeds each serves",
        "description": "The Game Pulse sample games, newest first. The retained Portland version 1 example (0022501147) is served at its feed route but is not listed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "The fixture index.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Access-Control-Expose-Headers": {
                "$ref": "#/components/headers/AccessControlExposeHeaders"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureIndex"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          }
        }
      },
      "head": {
        "operationId": "headNbaAiInsightsFixtures",
        "summary": "The fixture index headers without a body",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "The GET headers.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Access-Control-Expose-Headers": {
                "$ref": "#/components/headers/AccessControlExposeHeaders"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          }
        }
      },
      "options": {
        "operationId": "preflightNbaAiInsightsFixtures",
        "summary": "CORS preflight",
        "responses": {
          "204": {
            "$ref": "#/components/responses/Preflight"
          }
        }
      }
    },
    "/v1/fixtures/{fixtureId}/feeds/{feedKey}": {
      "get": {
        "operationId": "getNbaAiInsightsFixtureFeed",
        "summary": "Get the complete active NBA AI Insights snapshot for one fixture",
        "description": "A bundled sample fixture, or the deployment's public live feed for the fixture, served with Cache-Control: no-store. No authentication.",
        "parameters": [
          {
            "$ref": "#/components/parameters/FixtureId"
          },
          {
            "$ref": "#/components/parameters/FeedKey"
          },
          {
            "$ref": "#/components/parameters/AtAction"
          },
          {
            "$ref": "#/components/parameters/AsOf"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Complete currently consumable NBA AI Insights snapshot, ordered by active-revision publishedAt newest first with id as the tie-break. With atAction or asOf, the replay snapshot at that point: the same order, snapshotAt recomputed from the items kept (an empty replay snapshot reports the fixture's first play-by-play event time, or asOf when that is earlier) and its own ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Access-Control-Expose-Headers": {
                "$ref": "#/components/headers/AccessControlExposeHeaders"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NbaAiInsightsFeed"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          }
        }
      },
      "head": {
        "operationId": "headNbaAiInsightsFixtureFeed",
        "summary": "The snapshot headers without a body",
        "parameters": [
          {
            "$ref": "#/components/parameters/FixtureId"
          },
          {
            "$ref": "#/components/parameters/FeedKey"
          },
          {
            "$ref": "#/components/parameters/AtAction"
          },
          {
            "$ref": "#/components/parameters/AsOf"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "The GET headers.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Access-Control-Expose-Headers": {
                "$ref": "#/components/headers/AccessControlExposeHeaders"
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Invalid replay parameter."
          },
          "404": {
            "description": "Unknown fixture or feed, or a feed the deployment does not serve publicly."
          }
        }
      },
      "options": {
        "operationId": "preflightNbaAiInsightsFixtureFeed",
        "summary": "CORS preflight",
        "parameters": [
          {
            "$ref": "#/components/parameters/FixtureId"
          },
          {
            "$ref": "#/components/parameters/FeedKey"
          }
        ],
        "responses": {
          "204": {
            "$ref": "#/components/responses/Preflight"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "FixtureId": {
        "name": "fixtureId",
        "in": "path",
        "required": true,
        "description": "NBA game ID used as the integrating client's stable fixture identifier.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "FeedKey": {
        "name": "feedKey",
        "in": "path",
        "required": true,
        "description": "Client-recognized feed key. The NBA feed is pulse.",
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
        }
      },
      "AtAction": {
        "name": "atAction",
        "in": "query",
        "required": false,
        "description": "Replay: keep only items whose content.actionNumber (the NBA play-by-play actionNumber they attach to) is at or before this value. Sample games and public live feeds; the Portland version 1 fixture returns 400.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "maximum": 999999999
        }
      },
      "AsOf": {
        "name": "asOf",
        "in": "query",
        "required": false,
        "description": "Replay: keep only items whose publishedAt is at or before this RFC 3339 date-time, which must carry a time zone (encode + as %2B). Combined with atAction, an item must satisfy both. Sample games and public live feeds; the Portland version 1 fixture returns 400.",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "ETag": {
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "AccessControlAllowOrigin": {
        "required": true,
        "schema": {
          "const": "*"
        }
      },
      "AccessControlExposeHeaders": {
        "required": true,
        "schema": {
          "const": "ETag"
        }
      }
    },
    "responses": {
      "NotModified": {
        "description": "The snapshot has not changed.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/AccessControlAllowOrigin"
          },
          "Access-Control-Expose-Headers": {
            "$ref": "#/components/headers/AccessControlExposeHeaders"
          }
        }
      },
      "Preflight": {
        "description": "CORS preflight accepted.",
        "headers": {
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/AccessControlAllowOrigin"
          },
          "Access-Control-Allow-Methods": {
            "schema": {
              "const": "GET, HEAD, OPTIONS"
            }
          },
          "Access-Control-Allow-Headers": {
            "schema": {
              "const": "If-None-Match, Authorization"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "Only GET, HEAD and OPTIONS are supported.",
        "headers": {
          "Allow": {
            "schema": {
              "const": "GET, HEAD, OPTIONS"
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem": {
        "description": "Request could not be fulfilled.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "FixtureIndex": {
        "$ref": "./nba-ai-insights-feed.schema.json#/$defs/fixtureIndex"
      },
      "NbaAiInsightsFeed": {
        "allOf": [
          {
            "$ref": "./content-feed.schema.json"
          },
          {
            "type": "object",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/NbaAiInsightsItem"
                }
              }
            }
          }
        ]
      },
      "NbaAiInsightsItem": {
        "description": "One NBA item, discriminated by definitionKey. nba.player-performance-summary has two definition versions, told apart by definitionVersion: 1 (the Portland example) and 2 (the sample games). Version 2 statistic values use the scopes currentGame, seasonAverage, postseasonAverage, lastSeasonAverage (the previous regular season, carried in a season's opening weeks), recentGame, seasonHigh, postseasonHigh, careerHigh and careerPlayoffHigh.",
        "oneOf": [
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/initialGameEntryItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/postGameItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/preGameItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/breakItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/playerPerformanceItemVersions"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/teamPerformanceItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/fourFactorsItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/pointBreakdownItem"
          },
          {
            "$ref": "./nba-ai-insights-feed.schema.json#/$defs/defensiveItem"
          }
        ],
        "discriminator": {
          "propertyName": "definitionKey",
          "mapping": {
            "nba.initial-game-entry-summary": "./nba-ai-insights-feed.schema.json#/$defs/initialGameEntryItem",
            "nba.post-game-summary": "./nba-ai-insights-feed.schema.json#/$defs/postGameItem",
            "nba.pre-game-summary": "./nba-ai-insights-feed.schema.json#/$defs/preGameItem",
            "nba.timeout-quarter-halftime-summary": "./nba-ai-insights-feed.schema.json#/$defs/breakItem",
            "nba.player-performance-summary": "./nba-ai-insights-feed.schema.json#/$defs/playerPerformanceItemVersions",
            "nba.team-performance-summary": "./nba-ai-insights-feed.schema.json#/$defs/teamPerformanceItem",
            "nba.four-factors": "./nba-ai-insights-feed.schema.json#/$defs/fourFactorsItem",
            "nba.point-breakdown": "./nba-ai-insights-feed.schema.json#/$defs/pointBreakdownItem",
            "nba.defensive-summary": "./nba-ai-insights-feed.schema.json#/$defs/defensiveItem"
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri-reference"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string",
            "format": "uri-reference"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
