Repository: ogen-go/ogen
Pull request #184 (2022-02-14 10:16:29)

fix(parser): handle cyclic references


Patch:
diff --git a/internal/oas/parser/parse_parameter.go b/internal/oas/parser/parse_parameter.go
index ab867f96..fd622769 100644
--- a/internal/oas/parser/parse_parameter.go
+++ b/internal/oas/parser/parse_parameter.go
@@ -22,7 +22,7 @@ func (p *parser) parseParams(params []*ogen.Parameter) ([]*oas.Parameter, error)
 	)
 
 	for _, spec := range params {
-		param, err := p.parseParameter(spec)
+		param, err := p.parseParameter(spec, resolveCtx{})
 		if err != nil {
 			return nil, errors.Wrapf(err, "parse parameter %q", spec.Name)
 		}
@@ -42,9 +42,9 @@ func (p *parser) parseParams(params []*ogen.Parameter) ([]*oas.Parameter, error)
 	return result, nil
 }
 
-func (p *parser) parseParameter(param *ogen.Parameter) (*oas.Parameter, error) {
+func (p *parser) parseParameter(param *ogen.Parameter, ctx resolveCtx) (*oas.Parameter, error) {
 	if ref := param.Ref; ref != "" {
-		parsed, err := p.resolveParameter(ref)
+		parsed, err := p.resolveParameter(ref, ctx)
 		if err != nil {
 			return nil, errors.Wrapf(err, "resolve %q reference", ref)
 		}
diff --git a/internal/oas/parser/parse_request_body.go b/internal/oas/parser/parse_request_body.go
index 73c4aa86..83862c31 100644
--- a/internal/oas/parser/parse_request_body.go
+++ b/internal/oas/parser/parse_request_body.go
@@ -8,9 +8,9 @@ import (
 	"github.com/ogen-go/ogen/jsonschema"
 )
 
-func (p *parser) parseRequestBody(body *ogen.RequestBody) (*oas.RequestBody, error) {
+func (p *parser) parseRequestBody(body *ogen.RequestBody, ctx resolveCtx) (*oas.RequestBody, error) {
 	if ref := body.Ref; ref != "" {
-		reqBody, err := p.resolveRequestBody(ref)
+		reqBody, err := p.resolveRequestBody(ref, ctx)
 		if err != nil {
 			return nil, errors.Wrapf(err, "resolve %q reference", ref)
 		}
diff --git a/internal/oas/parser/parse_response.go b/internal/oas/parser/parse_response.go
index 63328692..ebf57aff 100644
--- a/internal/oas/parser/parse_response.go
+++ b/internal/oas/parser/parse_response.go
@@ -22,7 +22,7 @@ func (p *parser) parseResponses(responses ogen.Responses) (map[string]*oas.Respo
 			return nil, errors.Wrap(err, status)
 		}
 
-		resp, err := p.parseResponse(response)
+		resp, err := p.parseResponse(response, resolveCtx{})
 		if err != nil {
 			return nil, errors.Wrap(err, status)
 		}
@@ -33,9 +33,9 @@ func (p *parser) parseResponses(responses ogen.Responses) (map[string]*oas.Respo
 	return result, nil
 }
 
-func (p *parser) parseResponse(resp *ogen.Response) (*oas.Response, error) {
+func (p *parser) parseResponse(resp *ogen.Response, ctx resolveCtx) (*oas.Response, error) {
 	if ref := resp.Ref; ref != "" {
-		resp, err := p.resolveResponse(ref)
+		resp, err := p.resolveResponse(ref, ctx)
 		if err != nil {
 			return nil, errors.Wrapf(err, "resolve %q reference", ref)
 		}
diff --git a/internal/oas/parser/parser.go b/internal/oas/parser/parser.go
index 37898cba..7e7e5387 100644
--- a/internal/oas/parser/parser.go
+++ b/internal/oas/parser/parser.go
@@ -108,7 +108,7 @@ func (p *parser) parseOp(path, httpMethod string, spec ogen.Operation, itemParam
 	}
 
 	if spec.RequestBody != nil {
-		op.RequestBody, err = p.parseRequestBody(spec.RequestBody)
+		op.RequestBody, err = p.parseRequestBody(spec.RequestBody, resolveCtx{})
 		if err != nil {
 			return nil, errors.Wrap(err, "requestBody")
 		}
diff --git a/internal/oas/parser/ref.go b/internal/oas/parser/ref.go
index 7bfaef2d..1cd7c408 100644
--- a/internal/oas/parser/ref.go
+++ b/internal/oas/parser/ref.go
@@ -10,6 +10,8 @@ import (
 	"github.com/ogen-go/ogen/jsonschema"
 )
 
+type resolveCtx map[string]struct{}
+
 type componentsResolver map[string]*ogen.Schema
 
 func (c componentsResolver) ResolveReference(ref string) (*jsonschema.RawSchema, error) {
@@ -27,7 +29,7 @@ func (c componentsResolver) ResolveReference(ref string) (*jsonschema.RawSchema,
 	return s.ToJSONSchema(), nil
 }
 
-func (p *parser) resolveRequestBody(ref string) (*oas.RequestBody, error) {
+func (p *parser) resolveRequestBody(ref string, ctx resolveCtx) (*oas.RequestBody, error) {
 	const prefix = "#/components/requestBodies/"
 	if !strings.HasPrefix(ref, prefix) {
 		return nil, errors.Errorf("invalid requestBody reference: %q", ref)
@@ -37,13 +39,18 @@ func (p *parser) resolveRequestBody(ref string) (*oas.RequestBody, error) {
 		return r, nil
 	}
 
+	if _, ok := ctx[ref]; ok {
+		return nil, errors.Errorf("infinite recursion: %q", ref)
+	}
+	ctx[ref] = struct{}{}
+
 	name := strings.TrimPrefix(ref, prefix)
 	component, found := p.spec.Components.RequestBodies[name]
 	if !found {
 		return nil, errors.Errorf("component by reference %q not found", ref)
 	}
 
-	r, err := p.parseRequestBody(component)
+	r, err := p.parseRequestBody(component, ctx)
 	if err != nil {
 		return nil, err
 	}
@@ -52,7 +59,7 @@ func (p *parser) resolveRequestBody(ref string) (*oas.RequestBody, error) {
 	return r, nil
 }
 
-func (p *parser) resolveResponse(ref string) (*oas.Response, error) {
+func (p *parser) resolveResponse(ref string, ctx resolveCtx) (*oas.Response, error) {
 	const prefix = "#/components/responses/"
 	if !strings.HasPrefix(ref, prefix) {
 		return nil, errors.Errorf("invalid response reference: %q", ref)
@@ -62,13 +69,18 @@ func (p *parser) resolveResponse(ref string) (*oas.Response, error) {
 		return r, nil
 	}
 
+	if _, ok := ctx[ref]; ok {
+		return nil, errors.Errorf("infinite recursion: %q", ref)
+	}
+	ctx[ref] = struct{}{}
+
 	name := strings.TrimPrefix(ref, prefix)
 	component, found := p.spec.Components.Responses[name]
 	if !found {
 		return nil, errors.Errorf("component by reference %q not found", ref)
 	}
 
-	r, err := p.parseResponse(component)
+	r, err := p.parseResponse(component, ctx)
 	if err != nil {
 		return nil, err
 	}
@@ -78,7 +90,7 @@ func (p *parser) resolveResponse(ref string) (*oas.Response, error) {
 	return r, nil
 }
 
-func (p *parser) resolveParameter(ref string) (*oas.Parameter, error) {
+func (p *parser) resolveParameter(ref string, ctx resolveCtx) (*oas.Parameter, error) {
 	const prefix = "#/components/parameters/"
 	if !strings.HasPrefix(ref, prefix) {
 		return nil, errors.Errorf("invalid parameter reference: %q", ref)
@@ -88,13 +100,18 @@ func (p *parser) resolveParameter(ref string) (*oas.Parameter, error) {
 		return param, nil
 	}
 
+	if _, ok := ctx[ref]; ok {
+		return nil, errors.Errorf("infinite recursion: %q", ref)
+	}
+	ctx[ref] = struct{}{}
+
 	name := strings.TrimPrefix(ref, prefix)
 	component, found := p.spec.Components.Parameters[name]
 	if !found {
 		return nil, errors.Errorf("component by reference %q not found", ref)
 	}
 
-	param, err := p.parseParameter(component)
+	param, err := p.parseParameter(component, ctx)
 	if err != nil {
 		return nil, err
 	}
diff --git a/jsonschema/parser.go b/jsonschema/parser.go
index 137be4ff..3fa6f5fb 100644
--- a/jsonschema/parser.go
+++ b/jsonschema/parser.go
@@ -26,7 +26,7 @@ func NewParser(s Settings) *Parser {
 }
 
 func (p *Parser) Parse(schema *RawSchema) (*Schema, error) {
-	return p.parse(schema, nil)
+	return p.parse(schema, resolveCtx{})
 }
 
 func (p *Parser) parse(schema *RawSchema, ctx resolveCtx) (*Schema, error) {
@@ -298,13 +298,10 @@ func (p *Parser) resolve(ref string, ctx resolveCtx) (*Schema, error) {
 	if s, ok := p.refcache[ref]; ok {
 		return s, nil
 	}
+
 	if _, ok := ctx[ref]; ok {
 		return nil, errors.Errorf("infinite recursion: %q", ref)
 	}
-
-	if ctx == nil {
-		ctx = resolveCtx{}
-	}
 	ctx[ref] = struct{}{}
 
 	raw, err := p.resolver.ResolveReference(ref)


Test patch:
diff --git a/_testdata/negative/api_v3.json b/_testdata/negative/api_v3.json
new file mode 100644
index 00000000..45950ae8
--- /dev/null
+++ b/_testdata/negative/api_v3.json
@@ -0,0 +1,7181 @@
+{
+  "openapi": "3.0.1",
+  "info": {
+    "title": "The Blue Alliance API v3",
+    "description": "# Overview \n\n Information and statistics about FIRST Robotics Competition teams and events. \n\n# Authentication \n\nAll endpoints require an Auth Key to be passed in the header `X-TBA-Auth-Key`. If you do not have an auth key yet, you can obtain one from your [Account Page](/account). \n\n A `User-Agent` header may need to be set to prevent a 403 Unauthorized error.",
+    "version": "3.8.0",
+    "x-version-info": "Versions of the API follow the format X.Y.Z, with X being a major version, Y denoting the minor version, and Z the point release. Changes to the spec or API that result in a major version change will significantly impact implementations. Changes to the minor version indicate paths and/or fields in existing models may be added, and any breaking changes will be confined to paths or models listed as in-development in the prior minor version. Changes to the point release indicate no format or structure changes to the paths or models, but updated or clarified documentation. Note that changes to paths and models refer to the actual result from the API, not the documentation.",
+    "x-changes": "3.8.0-3.8.1: Added Webcast date field. 3.7.0-3.8.0: Added 2020 Match Breakdown. 3.6.0-3.7.0: Added Zebra MotionWorks endpoints and models. 3.5.2-3.6.0: Added `school_name` to the Team model. 3.5.1-3.5.2: Removed `key` from the Media object, set `foreign_key` as a required property. 3.5-3.5.1: Fixed api clients crashing when requesting simple matches resulting in ties. 3.04.1 - 3.5: Updated the spec to follow OpenAPI standards. 3.04.0 - 3.04.1: Team motto will now return null. 3.03.1 - 3.04.0: Add direct_url and view_url to the Media model. 3.03.0 - 3.03.1: Fix model of /team/{team_key}/robots to match API, add min and max for year and add min for page_num. 3.02.1 - 3.03.0: Added Timeseries models and endpoints. 3.02.0 - 3.02.1: Fixed the model for `/team/{team_key}/districts` to match return from API. 3.1.0 - 3.02.0: Added `tba_gameData` to score breakdown and a leading zero to the minor version number to allow for easier sorting later. 3.0.5 - 3.1.0: Version bump for 2018 added fields and endpoints. Models Updated: `Team_Event_Status`, `Media`, 2018 Score Breakdowns. Endpoints Added: `/team/{team_key}/events/{year}/statuses`, `/event/{event_key}/teams/statuses` 3.0.4 - 3.0.5: Minor spelling fixes. Remove 2016 fields from `Match_Score_Breakdown_2017_Alliance` model. Fix `first_event_id` in `Event` model to correct type. Update `Media`.`type` enum. --- 3.0.3 - 3.0.4: Correct syntax in `Team_Event_Status_playoff` object, include descriptions in `Event_District_Points` and fix the path in `Team_Event_Status_playoff.properties.record` in order to more closely match Swagger spec. Fix syntax of `Match.video` to be correct and accurately reflect what is returned by the API. --- 3.0.2 - 3.0.3: `extra_stats` and `extra_stats_info` added to `Event_Ranking` model. Corrected match video property claiming to use the `Media` model, which it doesn't. Added `first_event_code` to the `Event` model. Added `/team/{team_key}/media/tag/{media_tag}` and year endpoints. Added `dq_team_keys` to `Match_alliance` model.  --- 3.0.1 - 3.0.2: `Team_Event_Status` and `Event_Ranking` model documentation changed to reflect actual API return. Changes involved W-L-T and ranking properties. --- 3.0.0 - 3.0.1: Descriptions updated to clarify some terms and improve grammar. The `district` property on the `Event` object now points to the `District_List` model, which was identical. `Required` fields on fully documented models now represent fields that may not be `null`. `District_Ranking` model documented."
+  },
+  "servers": [
+    {
+      "url": "https://www.thebluealliance.com/api/v3"
+    }
+  ],
+  "tags": [
+    {
+      "name": "TBA",
+      "description": "Calls that expose TBA internals or status."
+    },
+    {
+      "name": "list",
+      "description": "Calls that return a list of records."
+    },
+    {
+      "name": "team",
+      "description": "Calls that return team or team-specific information."
+    },
+    {
+      "name": "event",
+      "description": "Calls that return event, or event-specific information."
+    },
+    {
+      "name": "match",
+      "description": "Calls that return match, or match-specific information."
+    },
+    {
+      "name": "district",
+      "description": "Calls that return district, or district-related information."
+    }
+  ],
+  "paths": {
+    "/status": {
+      "get": {
+        "tags": [
+          "TBA"
+        ],
+        "description": "Returns API status, and TBA status information.",
+        "operationId": "getStatus",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/API_Status"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/teams/{page_num}": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` objects, paginated in groups of 500.",
+        "operationId": "getTeams",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/teams/{page_num}/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of short form `Team_Simple` objects, paginated in groups of 500.",
+        "operationId": "getTeamsSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      },
+      "x-comment": "Simple (non-full) responses need a separate path definition. See also https://github.com/OAI/OpenAPI-Specification/issues/270"
+    },
+    "/teams/{page_num}/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of Team keys, paginated in groups of 500. (Note, each page will not have 500 teams, but will include the teams within that range of 500.)",
+        "operationId": "getTeamsKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/teams/{year}/{page_num}": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` objects that competed in the given year, paginated in groups of 500.",
+        "operationId": "getTeamsByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/teams/{year}/{page_num}/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of short form `Team_Simple` objects that competed in the given year, paginated in groups of 500.",
+        "operationId": "getTeamsByYearSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/teams/{year}/{page_num}/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "list"
+        ],
+        "description": "Gets a list Team Keys that competed in the given year, paginated in groups of 500.",
+        "operationId": "getTeamsByYearKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          },
+          {
+            "$ref": "#/components/parameters/page_num"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Team Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a `Team` object for the team referenced by the given key.",
+        "operationId": "getTeam",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Team"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/simple": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a `Team_Simple` object for the team referenced by the given key.",
+        "operationId": "getTeamSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Team_Simple"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/years_participated": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of years in which the team participated in at least one competition.",
+        "operationId": "getTeamYearsParticipated",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "integer"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/districts": {
+      "get": {
+        "tags": [
+          "team",
+          "district"
+        ],
+        "description": "Gets an array of districts representing each year the team was in a district. Will return an empty array if the team was never in a district.",
+        "operationId": "getTeamDistricts",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/District_List"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/robots": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of year and robot name pairs for each year that a robot name was provided. Will return an empty array if the team has never named a robot.",
+        "operationId": "getTeamRobots",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team_Robot"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a list of all events this team has competed at.",
+        "operationId": "getTeamEvents",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a short-form list of all events this team has competed at.",
+        "operationId": "getTeamEventsSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a list of the event keys for all events this team has competed at.",
+        "operationId": "getTeamEventsKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Event Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/{year}": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a list of events this team has competed at in the given year.",
+        "operationId": "getTeamEventsByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/{year}/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a short-form list of events this team has competed at in the given year.",
+        "operationId": "getTeamEventsByYearSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/{year}/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a list of the event keys for events this team has competed at in the given year.",
+        "operationId": "getTeamEventsByYearKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Event Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/events/{year}/statuses": {
+      "get": {
+        "tags": [
+          "list",
+          "team",
+          "event"
+        ],
+        "description": "Gets a key-value list of the event statuses for events this team has competed at in the given year.",
+        "operationId": "getTeamEventsStatusesByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object",
+                  "additionalProperties": {
+                    "$ref": "#/components/schemas/Team_Event_Status"
+                  },
+                  "description": "A key-value pair of `Team_Event_Status` objects with the event key as the key."
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/event/{event_key}/matches": {
+      "get": {
+        "tags": [
+          "team",
+          "event",
+          "match"
+        ],
+        "description": "Gets a list of matches for the given team and event.",
+        "operationId": "getTeamEventMatches",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/event/{event_key}/matches/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "event",
+          "match"
+        ],
+        "description": "Gets a short-form list of matches for the given team and event.",
+        "operationId": "getTeamEventMatchesSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/event/{event_key}/matches/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "event",
+          "match"
+        ],
+        "description": "Gets a list of match keys for matches for the given team and event.",
+        "operationId": "getTeamEventMatchesKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Match Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/event/{event_key}/awards": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets a list of awards the given team won at the given event.",
+        "operationId": "getTeamEventAwards",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Award"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/event/{event_key}/status": {
+      "get": {
+        "tags": [
+          "team",
+          "event"
+        ],
+        "description": "Gets the competition rank and status of the team at the given event.",
+        "operationId": "getTeamEventStatus",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Team_Event_Status"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/awards": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of awards the given team has won.",
+        "operationId": "getTeamAwards",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Award"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/awards/{year}": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of awards the given team has won in a given year.",
+        "operationId": "getTeamAwardsByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Award"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/matches/{year}": {
+      "get": {
+        "tags": [
+          "team",
+          "match"
+        ],
+        "description": "Gets a list of matches for the given team and year.",
+        "operationId": "getTeamMatchesByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/matches/{year}/simple": {
+      "get": {
+        "tags": [
+          "team",
+          "match"
+        ],
+        "description": "Gets a short-form list of matches for the given team and year.",
+        "operationId": "getTeamMatchesByYearSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/matches/{year}/keys": {
+      "get": {
+        "tags": [
+          "team",
+          "match"
+        ],
+        "description": "Gets a list of match keys for matches for the given team and year.",
+        "operationId": "getTeamMatchesByYearKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Match Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/media/{year}": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of Media (videos / pictures) for the given team and year.",
+        "operationId": "getTeamMediaByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Media"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/media/tag/{media_tag}": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of Media (videos / pictures) for the given team and tag.",
+        "operationId": "getTeamMediaByTag",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/media_tag"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Media"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/media/tag/{media_tag}/{year}": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of Media (videos / pictures) for the given team, tag and year.",
+        "operationId": "getTeamMediaByTagYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          },
+          {
+            "$ref": "#/components/parameters/media_tag"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Media"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/team/{team_key}/social_media": {
+      "get": {
+        "tags": [
+          "team"
+        ],
+        "description": "Gets a list of Media (social media) for the given team.",
+        "operationId": "getTeamSocialMedia",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/team_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Media"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/events/{year}": {
+      "get": {
+        "tags": [
+          "event",
+          "list"
+        ],
+        "description": "Gets a list of events in the given year.",
+        "operationId": "getEventsByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/events/{year}/simple": {
+      "get": {
+        "tags": [
+          "event",
+          "list"
+        ],
+        "description": "Gets a short-form list of events in the given year.",
+        "operationId": "getEventsByYearSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/events/{year}/keys": {
+      "get": {
+        "tags": [
+          "event",
+          "list"
+        ],
+        "description": "Gets a list of event keys in the given year.",
+        "operationId": "getEventsByYearKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Event Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets an Event.",
+        "operationId": "getEvent",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/simple": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a short-form Event.",
+        "operationId": "getEventSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_Simple"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/alliances": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a list of Elimination Alliances for the given Event.",
+        "operationId": "getEventAlliances",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Elimination_Alliance"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/insights": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a set of Event-specific insights for the given Event.",
+        "operationId": "getEventInsights",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_Insights"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/oprs": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a set of Event OPRs (including OPR, DPR, and CCWM) for the given Event.",
+        "operationId": "getEventOPRs",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_OPRs"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/predictions": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets information on TBA-generated predictions for the given Event. Contains year-specific information. *WARNING* This endpoint is currently under development and may change at any time.",
+        "operationId": "getEventPredictions",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_Predictions"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/rankings": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a list of team rankings for the Event.",
+        "operationId": "getEventRankings",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_Ranking"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/district_points": {
+      "get": {
+        "tags": [
+          "event",
+          "district"
+        ],
+        "description": "Gets a list of team rankings for the Event.",
+        "operationId": "getEventDistrictPoints",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Event_District_Points"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/teams": {
+      "get": {
+        "tags": [
+          "event",
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` objects that competed in the given event.",
+        "operationId": "getEventTeams",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/teams/simple": {
+      "get": {
+        "tags": [
+          "event",
+          "team",
+          "list"
+        ],
+        "description": "Gets a short-form list of `Team` objects that competed in the given event.",
+        "operationId": "getEventTeamsSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/teams/keys": {
+      "get": {
+        "tags": [
+          "event",
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` keys that competed in the given event.",
+        "operationId": "getEventTeamsKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Team Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/teams/statuses": {
+      "get": {
+        "tags": [
+          "event",
+          "team",
+          "list"
+        ],
+        "description": "Gets a key-value list of the event statuses for teams competing at the given event.",
+        "operationId": "getEventTeamsStatuses",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object",
+                  "additionalProperties": {
+                    "$ref": "#/components/schemas/Team_Event_Status"
+                  },
+                  "description": "A key-value pair of `Team_Event_Status` objects with the event key as the key."
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/matches": {
+      "get": {
+        "tags": [
+          "event",
+          "match"
+        ],
+        "description": "Gets a list of matches for the given event.",
+        "operationId": "getEventMatches",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/matches/simple": {
+      "get": {
+        "tags": [
+          "event",
+          "match"
+        ],
+        "description": "Gets a short-form list of matches for the given event.",
+        "operationId": "getEventMatchesSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Match_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/matches/keys": {
+      "get": {
+        "tags": [
+          "event",
+          "match"
+        ],
+        "description": "Gets a list of match keys for the given event.",
+        "operationId": "getEventMatchesKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Match Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/matches/timeseries": {
+      "get": {
+        "tags": [
+          "event",
+          "match"
+        ],
+        "description": "Gets an array of Match Keys for the given event key that have timeseries data. Returns an empty array if no matches have timeseries data.\n*WARNING:* This is *not* official data, and is subject to a significant possibility of error, or missing data. Do not rely on this data for any purpose. In fact, pretend we made it up.\n*WARNING:* This endpoint and corresponding data models are under *active development* and may change at any time, including in breaking ways.",
+        "operationId": "getEventMatchTimeseries",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "string",
+                    "description": "Match Key"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/event/{event_key}/awards": {
+      "get": {
+        "tags": [
+          "event"
+        ],
+        "description": "Gets a list of awards from the given event.",
+        "operationId": "getEventAwards",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/event_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Award"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/match/{match_key}": {
+      "get": {
+        "tags": [
+          "match"
+        ],
+        "description": "Gets a `Match` object for the given match key.",
+        "operationId": "getMatch",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/match_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Match"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/match/{match_key}/simple": {
+      "get": {
+        "tags": [
+          "match"
+        ],
+        "description": "Gets a short-form `Match` object for the given match key.",
+        "operationId": "getMatchSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/match_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Match_Simple"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/match/{match_key}/timeseries": {
+      "get": {
+        "tags": [
+          "match"
+        ],
+        "description": "Gets an array of game-specific Match Timeseries objects for the given match key or an empty array if not available.\n*WARNING:* This is *not* official data, and is subject to a significant possibility of error, or missing data. Do not rely on this data for any purpose. In fact, pretend we made it up.\n*WARNING:* This endpoint and corresponding data models are under *active development* and may change at any time, including in breaking ways.",
+        "operationId": "getMatchTimeseries",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/match_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "object",
+                    "properties": {}
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/match/{match_key}/zebra_motionworks": {
+      "get": {
+        "tags": [
+          "match"
+        ],
+        "description": "Gets Zebra MotionWorks data for a Match for the given match key.",
+        "operationId": "getMatchZebra",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/match_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/Zebra"
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/districts/{year}": {
+      "get": {
+        "tags": [
+          "district"
+        ],
+        "description": "Gets a list of districts and their corresponding district key, for the given year.",
+        "operationId": "getDistrictsByYear",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/year"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/District_List"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/events": {
+      "get": {
+        "tags": [
+          "district",
+          "event",
+          "list"
+        ],
+        "description": "Gets a list of events in the given district.",
+        "operationId": "getDistrictEvents",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/events/simple": {
+      "get": {
+        "tags": [
+          "district",
+          "event",
+          "list"
+        ],
+        "description": "Gets a short-form list of events in the given district.",
+        "operationId": "getDistrictEventsSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "name": "district_key",
+            "in": "path",
+            "description": "TBA District Key, eg `2016fim`",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Event_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/events/keys": {
+      "get": {
+        "tags": [
+          "district",
+          "event",
+          "list"
+        ],
+        "description": "Gets a list of event keys for events in the given district.",
+        "operationId": "getDistrictEventsKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Event Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/teams": {
+      "get": {
+        "tags": [
+          "district",
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` objects that competed in events in the given district.",
+        "operationId": "getDistrictTeams",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/teams/simple": {
+      "get": {
+        "tags": [
+          "district",
+          "team",
+          "list"
+        ],
+        "description": "Gets a short-form list of `Team` objects that competed in events in the given district.",
+        "operationId": "getDistrictTeamsSimple",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Team_Simple"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/teams/keys": {
+      "get": {
+        "tags": [
+          "district",
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of `Team` objects that competed in events in the given district.",
+        "operationId": "getDistrictTeamsKeys",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "description": "Array of Team Keys",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    },
+    "/district/{district_key}/rankings": {
+      "get": {
+        "tags": [
+          "district",
+          "team",
+          "list"
+        ],
+        "description": "Gets a list of team district rankings for the given district.",
+        "operationId": "getDistrictRankings",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/If-Modified-Since"
+          },
+          {
+            "$ref": "#/components/parameters/district_key"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Successful response",
+            "headers": {
+              "Cache-Control": {
+                "description": "The `Cache-Control` header, in particular the `max-age` value, contains the number of seconds the result should be considered valid for. During this time subsequent calls should return from the local cache directly.",
+                "schema": {
+                  "type": "string"
+                }
+              },
+              "Last-Modified": {
+                "description": "Indicates the date and time the data returned was last updated. Used by clients in the `If-Modified-Since` request header.",
+                "schema": {
+                  "type": "string"
+                }
+              }
+            },
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/District_Ranking"
+                  }
+                }
+              }
+            }
+          },
+          "304": {
+            "$ref": "#/components/responses/NotModified"
+          },
+          "401": {
+            "$ref": "#/components/responses/Unauthorized"
+
+          }
+        },
+        "security": [
+          {
+            "apiKey": []
+          }
+        ]
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "API_Status": {
+        "required": [
+          "android",
+          "current_season",
+          "down_events",
+          "ios",
+          "is_datafeed_down",
+          "max_season"
+        ],
+        "type": "object",
+        "properties": {
+          "current_season": {
+            "type": "integer",
+            "description": "Year of the current FRC season."
+          },
+          "max_season": {
+            "type": "integer",
+            "description": "Maximum FRC season year for valid queries."
+          },
+          "is_datafeed_down": {
+            "type": "boolean",
+            "description": "True if the entire FMS API provided by FIRST is down."
+          },
+          "down_events": {
+            "type": "array",
+            "description": "An array of strings containing event keys of any active events that are no longer updating.",
+            "items": {
+              "type": "string"
+            }
+          },
+          "ios": {
+            "$ref": "#/components/schemas/API_Status_App_Version"
+          },
+          "android": {
+            "$ref": "#/components/schemas/API_Status_App_Version"
+          }
+        }
+      },
+      "API_Status_App_Version": {
+        "required": [
+          "latest_app_version",
+          "min_app_version"
+        ],
+        "type": "object",
+        "properties": {
+          "min_app_version": {
+            "type": "integer",
+            "description": "Internal use - Minimum application version required to correctly connect and process data."
+          },
+          "latest_app_version": {
+            "type": "integer",
+            "description": "Internal use - Latest application version available."
+          }
+        }
+      },
+      "Team_Simple": {
+        "required": [
+          "key",
+          "name",
+          "team_number"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA team key with the format `frcXXXX` with `XXXX` representing the team number."
+          },
+          "team_number": {
+            "type": "integer",
+            "description": "Official team number issued by FIRST."
+          },
+          "nickname": {
+            "type": "string",
+            "description": "Team nickname provided by FIRST."
+          },
+          "name": {
+            "type": "string",
+            "description": "Official long name registered with FIRST."
+          },
+          "city": {
+            "type": "string",
+            "description": "City of team derived from parsing the address registered with FIRST."
+          },
+          "state_prov": {
+            "type": "string",
+            "description": "State of team derived from parsing the address registered with FIRST."
+          },
+          "country": {
+            "type": "string",
+            "description": "Country of team derived from parsing the address registered with FIRST."
+          }
+        }
+      },
+      "Team": {
+        "required": [
+          "key",
+          "name",
+          "team_number"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA team key with the format `frcXXXX` with `XXXX` representing the team number."
+          },
+          "team_number": {
+            "type": "integer",
+            "description": "Official team number issued by FIRST."
+          },
+          "nickname": {
+            "type": "string",
+            "description": "Team nickname provided by FIRST."
+          },
+          "name": {
+            "type": "string",
+            "description": "Official long name registered with FIRST."
+          },
+          "school_name": {
+            "type": "string",
+            "description": "Name of team school or affilited group registered with FIRST."
+          },
+          "city": {
+            "type": "string",
+            "description": "City of team derived from parsing the address registered with FIRST."
+          },
+          "state_prov": {
+            "type": "string",
+            "description": "State of team derived from parsing the address registered with FIRST."
+          },
+          "country": {
+            "type": "string",
+            "description": "Country of team derived from parsing the address registered with FIRST."
+          },
+          "address": {
+            "type": "string",
+            "description": "Will be NULL, for future development."
+          },
+          "postal_code": {
+            "type": "string",
+            "description": "Postal code from the team address."
+          },
+          "gmaps_place_id": {
+            "type": "string",
+            "description": "Will be NULL, for future development."
+          },
+          "gmaps_url": {
+            "type": "string",
+            "description": "Will be NULL, for future development.",
+            "format": "url"
+          },
+          "lat": {
+            "type": "number",
+            "description": "Will be NULL, for future development.",
+            "format": "double"
+          },
+          "lng": {
+            "type": "number",
+            "description": "Will be NULL, for future development.",
+            "format": "double"
+          },
+          "location_name": {
+            "type": "string",
+            "description": "Will be NULL, for future development."
+          },
+          "website": {
+            "type": "string",
+            "description": "Official website associated with the team.",
+            "format": "url"
+          },
+          "rookie_year": {
+            "type": "integer",
+            "description": "First year the team officially competed."
+          },
+          "motto": {
+            "type": "string",
+            "description": "Team's motto as provided by FIRST. This field is deprecated and will return null - will be removed at end-of-season in 2019."
+          },
+          "home_championship": {
+            "type": "object",
+            "properties": {},
+            "description": "Location of the team's home championship each year as a key-value pair. The year (as a string) is the key, and the city is the value."
+          }
+        }
+      },
+      "Team_Robot": {
+        "required": [
+          "key",
+          "robot_name",
+          "team_key",
+          "year"
+        ],
+        "type": "object",
+        "properties": {
+          "year": {
+            "type": "integer",
+            "description": "Year this robot competed in."
+          },
+          "robot_name": {
+            "type": "string",
+            "description": "Name of the robot as provided by the team."
+          },
+          "key": {
+            "type": "string",
+            "description": "Internal TBA identifier for this robot."
+          },
+          "team_key": {
+            "type": "string",
+            "description": "TBA team key for this robot."
+          }
+        }
+      },
+      "Event_Simple": {
+        "required": [
+          "end_date",
+          "event_code",
+          "event_type",
+          "key",
+          "name",
+          "start_date",
+          "year"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA event key with the format yyyy[EVENT_CODE], where yyyy is the year, and EVENT_CODE is the event code of the event."
+          },
+          "name": {
+            "type": "string",
+            "description": "Official name of event on record either provided by FIRST or organizers of offseason event."
+          },
+          "event_code": {
+            "type": "string",
+            "description": "Event short code, as provided by FIRST."
+          },
+          "event_type": {
+            "type": "integer",
+            "description": "Event Type, as defined here: https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/event_type.py#L2"
+          },
+          "district": {
+            "$ref": "#/components/schemas/District_List"
+          },
+          "city": {
+            "type": "string",
+            "description": "City, town, village, etc. the event is located in."
+          },
+          "state_prov": {
+            "type": "string",
+            "description": "State or Province the event is located in."
+          },
+          "country": {
+            "type": "string",
+            "description": "Country the event is located in."
+          },
+          "start_date": {
+            "type": "string",
+            "description": "Event start date in `yyyy-mm-dd` format.",
+            "format": "date"
+          },
+          "end_date": {
+            "type": "string",
+            "description": "Event end date in `yyyy-mm-dd` format.",
+            "format": "date"
+          },
+          "year": {
+            "type": "integer",
+            "description": "Year the event data is for."
+          }
+        }
+      },
+      "Event": {
+        "required": [
+          "end_date",
+          "event_code",
+          "event_type",
+          "event_type_string",
+          "key",
+          "name",
+          "start_date",
+          "year"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA event key with the format yyyy[EVENT_CODE], where yyyy is the year, and EVENT_CODE is the event code of the event."
+          },
+          "name": {
+            "type": "string",
+            "description": "Official name of event on record either provided by FIRST or organizers of offseason event."
+          },
+          "event_code": {
+            "type": "string",
+            "description": "Event short code, as provided by FIRST."
+          },
+          "event_type": {
+            "type": "integer",
+            "description": "Event Type, as defined here: https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/event_type.py#L2"
+          },
+          "district": {
+            "$ref": "#/components/schemas/District_List"
+          },
+          "city": {
+            "type": "string",
+            "description": "City, town, village, etc. the event is located in."
+          },
+          "state_prov": {
+            "type": "string",
+            "description": "State or Province the event is located in."
+          },
+          "country": {
+            "type": "string",
+            "description": "Country the event is located in."
+          },
+          "start_date": {
+            "type": "string",
+            "description": "Event start date in `yyyy-mm-dd` format.",
+            "format": "date"
+          },
+          "end_date": {
+            "type": "string",
+            "description": "Event end date in `yyyy-mm-dd` format.",
+            "format": "date"
+          },
+          "year": {
+            "type": "integer",
+            "description": "Year the event data is for."
+          },
+          "short_name": {
+            "type": "string",
+            "description": "Same as `name` but doesn't include event specifiers, such as 'Regional' or 'District'. May be null."
+          },
+          "event_type_string": {
+            "type": "string",
+            "description": "Event Type, eg Regional, District, or Offseason."
+          },
+          "week": {
+            "type": "integer",
+            "description": "Week of the event relative to the first official season event, zero-indexed. Only valid for Regionals, Districts, and District Championships. Null otherwise. (Eg. A season with a week 0 'preseason' event does not count, and week 1 events will show 0 here. Seasons with a week 0.5 regional event will show week 0 for those event(s) and week 1 for week 1 events and so on.)"
+          },
+          "address": {
+            "type": "string",
+            "description": "Address of the event's venue, if available."
+          },
+          "postal_code": {
+            "type": "string",
+            "description": "Postal code from the event address."
+          },
+          "gmaps_place_id": {
+            "type": "string",
+            "description": "Google Maps Place ID for the event address."
+          },
+          "gmaps_url": {
+            "type": "string",
+            "description": "Link to address location on Google Maps.",
+            "format": "url"
+          },
+          "lat": {
+            "type": "number",
+            "description": "Latitude for the event address.",
+            "format": "double"
+          },
+          "lng": {
+            "type": "number",
+            "description": "Longitude for the event address.",
+            "format": "double"
+          },
+          "location_name": {
+            "type": "string",
+            "description": "Name of the location at the address for the event, eg. Blue Alliance High School."
+          },
+          "timezone": {
+            "type": "string",
+            "description": "Timezone name."
+          },
+          "website": {
+            "type": "string",
+            "description": "The event's website, if any."
+          },
+          "first_event_id": {
+            "type": "string",
+            "description": "The FIRST internal Event ID, used to link to the event on the FRC webpage."
+          },
+          "first_event_code": {
+            "type": "string",
+            "description": "Public facing event code used by FIRST (on frc-events.firstinspires.org, for example)"
+          },
+          "webcasts": {
+            "type": "array",
+            "items": {
+              "$ref": "#/components/schemas/Webcast"
+            }
+          },
+          "division_keys": {
+            "type": "array",
+            "description": "An array of event keys for the divisions at this event.",
+            "items": {
+              "type": "string"
+            }
+          },
+          "parent_event_key": {
+            "type": "string",
+            "description": "The TBA Event key that represents the event's parent. Used to link back to the event from a division event. It is also the inverse relation of `divison_keys`."
+          },
+          "playoff_type": {
+            "type": "integer",
+            "description": "Playoff Type, as defined here: https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/playoff_type.py#L4, or null."
+          },
+          "playoff_type_string": {
+            "type": "string",
+            "description": "String representation of the `playoff_type`, or null."
+          }
+        }
+      },
+      "Team_Event_Status": {
+        "type": "object",
+        "properties": {
+          "qual": {
+            "$ref": "#/components/schemas/Team_Event_Status_rank"
+          },
+          "alliance": {
+            "$ref": "#/components/schemas/Team_Event_Status_alliance"
+          },
+          "playoff": {
+            "$ref": "#/components/schemas/Team_Event_Status_playoff"
+          },
+          "alliance_status_str": {
+            "type": "string",
+            "description": "An HTML formatted string suitable for display to the user containing the team's alliance pick status."
+          },
+          "playoff_status_str": {
+            "type": "string",
+            "description": "An HTML formatter string suitable for display to the user containing the team's playoff status."
+          },
+          "overall_status_str": {
+            "type": "string",
+            "description": "An HTML formatted string suitable for display to the user containing the team's overall status summary of the event."
+          },
+          "next_match_key": {
+            "type": "string",
+            "description": "TBA match key for the next match the team is scheduled to play in at this event, or null."
+          },
+          "last_match_key": {
+            "type": "string",
+            "description": "TBA match key for the last match the team played in at this event, or null."
+          }
+        }
+      },
+      "Team_Event_Status_rank": {
+        "type": "object",
+        "properties": {
+          "num_teams": {
+            "type": "integer",
+            "description": "Number of teams ranked."
+          },
+          "ranking": {
+            "type": "object",
+            "properties": {
+              "matches_played": {
+                "type": "integer",
+                "description": "Number of matches played."
+              },
+              "qual_average": {
+                "type": "number",
+                "description": "For some years, average qualification score. Can be null.",
+                "format": "double"
+              },
+              "sort_orders": {
+                "type": "array",
+                "description": "Ordered list of values used to determine the rank. See the `sort_order_info` property for the name of each value.",
+                "items": {
+                  "type": "number"
+                }
+              },
+              "record": {
+                "$ref": "#/components/schemas/WLT_Record"
+              },
+              "rank": {
+                "type": "integer",
+                "description": "Relative rank of this team."
+              },
+              "dq": {
+                "type": "integer",
+                "description": "Number of matches the team was disqualified for."
+              },
+              "team_key": {
+                "type": "string",
+                "description": "TBA team key for this rank."
+              }
+            }
+          },
+          "sort_order_info": {
+            "type": "array",
+            "description": "Ordered list of names corresponding to the elements of the `sort_orders` array.",
+            "items": {
+              "type": "object",
+              "properties": {
+                "precision": {
+                  "type": "integer",
+                  "description": "The number of digits of precision used for this value, eg `2` would correspond to a value of `101.11` while `0` would correspond to `101`."
+                },
+                "name": {
+                  "type": "string",
+                  "description": "The descriptive name of the value used to sort the ranking."
+                }
+              }
+            }
+          },
+          "status": {
+            "type": "string"
+          }
+        }
+      },
+      "Team_Event_Status_alliance": {
+        "required": [
+          "number",
+          "pick"
+        ],
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Alliance name, may be null."
+          },
+          "number": {
+            "type": "integer",
+            "description": "Alliance number."
+          },
+          "backup": {
+            "$ref": "#/components/schemas/Team_Event_Status_alliance_backup"
+          },
+          "pick": {
+            "type": "integer",
+            "description": "Order the team was picked in the alliance from 0-2, with 0 being alliance captain."
+          }
+        }
+      },
+      "Team_Event_Status_alliance_backup": {
+        "type": "object",
+        "properties": {
+          "out": {
+            "type": "string",
+            "description": "TBA key for the team replaced by the backup."
+          },
+          "in": {
+            "type": "string",
+            "description": "TBA key for the backup team called in."
+          }
+        },
+        "description": "Backup status, may be null."
+      },
+      "Team_Event_Status_playoff": {
+        "type": "object",
+        "properties": {
+          "level": {
+            "type": "string",
+            "description": "The highest playoff level the team reached.",
+            "enum": [
+              "qm",
+              "ef",
+              "qf",
+              "sf",
+              "f"
+            ]
+          },
+          "current_level_record": {
+            "$ref": "#/components/schemas/WLT_Record"
+          },
+          "record": {
+            "$ref": "#/components/schemas/WLT_Record"
+          },
+          "status": {
+            "type": "string",
+            "description": "Current competition status for the playoffs.",
+            "enum": [
+              "won",
+              "eliminated",
+              "playing"
+            ]
+          },
+          "playoff_average": {
+            "type": "integer",
+            "description": "The average match score during playoffs. Year specific. May be null if not relevant for a given year."
+          }
+        },
+        "description": "Playoff status for this team, may be null if the team did not make playoffs, or playoffs have not begun."
+      },
+      "Event_Ranking": {
+        "required": [
+          "rankings",
+          "sort_order_info"
+        ],
+        "type": "object",
+        "properties": {
+          "rankings": {
+            "type": "array",
+            "description": "List of rankings at the event.",
+            "items": {
+              "required": [
+                "dq",
+                "matches_played",
+                "rank",
+                "record",
+                "team_key"
+              ],
+              "type": "object",
+              "properties": {
+                "matches_played": {
+                  "type": "integer",
+                  "description": "Number of matches played by this team."
+                },
+                "qual_average": {
+                  "type": "integer",
+                  "description": "The average match score during qualifications. Year specific. May be null if not relevant for a given year."
+                },
+                "extra_stats": {
+                  "type": "array",
+                  "description": "Additional special data on the team's performance calculated by TBA.",
+                  "items": {
+                    "type": "number"
+                  }
+                },
+                "sort_orders": {
+                  "type": "array",
+                  "description": "Additional year-specific information, may be null. See parent `sort_order_info` for details.",
+                  "items": {
+                    "type": "number"
+                  }
+                },
+                "record": {
+                  "$ref": "#/components/schemas/WLT_Record"
+                },
+                "rank": {
+                  "type": "integer",
+                  "description": "The team's rank at the event as provided by FIRST."
+                },
+                "dq": {
+                  "type": "integer",
+                  "description": "Number of times disqualified."
+                },
+                "team_key": {
+                  "type": "string",
+                  "description": "The team with this rank."
+                }
+              }
+            }
+          },
+          "extra_stats_info": {
+            "type": "array",
+            "description": "List of special TBA-generated values provided in the `extra_stats` array for each item.",
+            "items": {
+              "required": [
+                "name",
+                "precision"
+              ],
+              "type": "object",
+              "properties": {
+                "precision": {
+                  "type": "number",
+                  "description": "Integer expressing the number of digits of precision in the number provided in `sort_orders`."
+                },
+                "name": {
+                  "type": "string",
+                  "description": "Name of the field used in the `extra_stats` array."
+                }
+              }
+            }
+          },
+          "sort_order_info": {
+            "type": "array",
+            "description": "List of year-specific values provided in the `sort_orders` array for each team.",
+            "items": {
+              "required": [
+                "name",
+                "precision"
+              ],
+              "type": "object",
+              "properties": {
+                "precision": {
+                  "type": "integer",
+                  "description": "Integer expressing the number of digits of precision in the number provided in `sort_orders`."
+                },
+                "name": {
+                  "type": "string",
+                  "description": "Name of the field used in the `sort_order` array."
+                }
+              }
+            }
+          }
+        }
+      },
+      "Event_District_Points": {
+        "required": [
+          "points"
+        ],
+        "type": "object",
+        "properties": {
+          "points": {
+            "type": "object",
+            "additionalProperties": {
+              "required": [
+                "alliance_points",
+                "award_points",
+                "elim_points",
+                "qual_points",
+                "total"
+              ],
+              "type": "object",
+              "properties": {
+                "total": {
+                  "type": "integer",
+                  "description": "Total points awarded at this event."
+                },
+                "alliance_points": {
+                  "type": "integer",
+                  "description": "Points awarded for alliance selection"
+                },
+                "elim_points": {
+                  "type": "integer",
+                  "description": "Points awarded for elimination match performance."
+                },
+                "award_points": {
+                  "type": "integer",
+                  "description": "Points awarded for event awards."
+                },
+                "qual_points": {
+                  "type": "integer",
+                  "description": "Points awarded for qualification match performance."
+                }
+              }
+            },
+            "description": "Points gained for each team at the event. Stored as a key-value pair with the team key as the key, and an object describing the points as its value."
+          },
+          "tiebreakers": {
+            "type": "object",
+            "additionalProperties": {
+              "type": "object",
+              "properties": {
+                "highest_qual_scores": {
+                  "type": "array",
+                  "items": {
+                    "type": "integer"
+                  }
+                },
+                "qual_wins": {
+                  "type": "integer"
+                }
+              }
+            },
+            "description": "Tiebreaker values for each team at the event. Stored as a key-value pair with the team key as the key, and an object describing the tiebreaker elements as its value."
+          }
+        }
+      },
+      "Event_Insights": {
+        "type": "object",
+        "properties": {
+          "qual": {
+            "type": "object",
+            "properties": {},
+            "description": "Inights for the qualification round of an event"
+          },
+          "playoff": {
+            "type": "object",
+            "properties": {},
+            "description": "Insights for the playoff round of an event"
+          }
+        },
+        "description": "A year-specific event insight object expressed as a JSON string, separated in to `qual` and `playoff` fields. See also Event_Insights_2016, Event_Insights_2017, etc."
+      },
+      "Event_Insights_2016": {
+        "required": [
+          "A_ChevalDeFrise",
+          "A_Portcullis",
+          "B_Moat",
+          "B_Ramparts",
+          "C_Drawbridge",
+          "C_SallyPort",
+          "D_RockWall",
+          "D_RoughTerrain",
+          "LowBar",
+          "average_auto_score",
+          "average_boulder_score",
+          "average_crossing_score",
+          "average_foul_score",
+          "average_high_goals",
+          "average_low_goals",
+          "average_score",
+          "average_tower_score",
+          "average_win_margin",
+          "average_win_score",
+          "breaches",
+          "captures",
+          "challenges",
+          "high_score",
+          "scales"
+        ],
+        "type": "object",
+        "properties": {
+          "LowBar": {
+            "type": "array",
+            "description": "For the Low Bar - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "A_ChevalDeFrise": {
+            "type": "array",
+            "description": "For the Cheval De Frise - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "A_Portcullis": {
+            "type": "array",
+            "description": "For the Portcullis - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "B_Ramparts": {
+            "type": "array",
+            "description": "For the Ramparts - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "B_Moat": {
+            "type": "array",
+            "description": "For the Moat - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "C_SallyPort": {
+            "type": "array",
+            "description": "For the Sally Port - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "C_Drawbridge": {
+            "type": "array",
+            "description": "For the Drawbridge - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "D_RoughTerrain": {
+            "type": "array",
+            "description": "For the Rough Terrain - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "D_RockWall": {
+            "type": "array",
+            "description": "For the Rock Wall - An array with three values, number of times damaged, number of opportunities to damage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "average_high_goals": {
+            "type": "number",
+            "description": "Average number of high goals scored.",
+            "format": "float"
+          },
+          "average_low_goals": {
+            "type": "number",
+            "description": "Average number of low goals scored.",
+            "format": "float"
+          },
+          "breaches": {
+            "type": "array",
+            "description": "An array with three values, number of times breached, number of opportunities to breach, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "scales": {
+            "type": "array",
+            "description": "An array with three values, number of times scaled, number of opportunities to scale, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "challenges": {
+            "type": "array",
+            "description": "An array with three values, number of times challenged, number of opportunities to challenge, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "captures": {
+            "type": "array",
+            "description": "An array with three values, number of times captured, number of opportunities to capture, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "average_win_score": {
+            "type": "number",
+            "description": "Average winning score.",
+            "format": "float"
+          },
+          "average_win_margin": {
+            "type": "number",
+            "description": "Average margin of victory.",
+            "format": "float"
+          },
+          "average_score": {
+            "type": "number",
+            "description": "Average total score.",
+            "format": "float"
+          },
+          "average_auto_score": {
+            "type": "number",
+            "description": "Average autonomous score.",
+            "format": "float"
+          },
+          "average_crossing_score": {
+            "type": "number",
+            "description": "Average crossing score.",
+            "format": "float"
+          },
+          "average_boulder_score": {
+            "type": "number",
+            "description": "Average boulder score.",
+            "format": "float"
+          },
+          "average_tower_score": {
+            "type": "number",
+            "description": "Average tower score.",
+            "format": "float"
+          },
+          "average_foul_score": {
+            "type": "number",
+            "description": "Average foul score.",
+            "format": "float"
+          },
+          "high_score": {
+            "type": "array",
+            "description": "An array with three values, high score, match key from the match with the high score, and the name of the match.",
+            "items": {
+              "type": "string"
+            }
+          }
+        },
+        "description": "Insights for FIRST Stronghold qualification and elimination matches."
+      },
+      "Event_Insights_2017": {
+        "required": [
+          "average_foul_score",
+          "average_fuel_points",
+          "average_fuel_points_auto",
+          "average_fuel_points_teleop",
+          "average_high_goals",
+          "average_high_goals_auto",
+          "average_high_goals_teleop",
+          "average_low_goals",
+          "average_low_goals_auto",
+          "average_low_goals_teleop",
+          "average_mobility_points_auto",
+          "average_points_auto",
+          "average_points_teleop",
+          "average_rotor_points",
+          "average_rotor_points_auto",
+          "average_rotor_points_teleop",
+          "average_score",
+          "average_takeoff_points_teleop",
+          "average_win_margin",
+          "average_win_score",
+          "high_kpa",
+          "high_score",
+          "kpa_achieved",
+          "mobility_counts",
+          "rotor_1_engaged",
+          "rotor_1_engaged_auto",
+          "rotor_2_engaged",
+          "rotor_2_engaged_auto",
+          "rotor_3_engaged",
+          "rotor_4_engaged",
+          "takeoff_counts",
+          "unicorn_matches"
+        ],
+        "type": "object",
+        "properties": {
+          "average_foul_score": {
+            "type": "number",
+            "description": "Average foul score.",
+            "format": "float"
+          },
+          "average_fuel_points": {
+            "type": "number",
+            "description": "Average fuel points scored.",
+            "format": "float"
+          },
+          "average_fuel_points_auto": {
+            "type": "number",
+            "description": "Average fuel points scored during auto.",
+            "format": "float"
+          },
+          "average_fuel_points_teleop": {
+            "type": "number",
+            "description": "Average fuel points scored during teleop.",
+            "format": "float"
+          },
+          "average_high_goals": {
+            "type": "number",
+            "description": "Average points scored in the high goal.",
+            "format": "float"
+          },
+          "average_high_goals_auto": {
+            "type": "number",
+            "description": "Average points scored in the high goal during auto.",
+            "format": "float"
+          },
+          "average_high_goals_teleop": {
+            "type": "number",
+            "description": "Average points scored in the high goal during teleop.",
+            "format": "float"
+          },
+          "average_low_goals": {
+            "type": "number",
+            "description": "Average points scored in the low goal.",
+            "format": "float"
+          },
+          "average_low_goals_auto": {
+            "type": "number",
+            "description": "Average points scored in the low goal during auto.",
+            "format": "float"
+          },
+          "average_low_goals_teleop": {
+            "type": "number",
+            "description": "Average points scored in the low goal during teleop.",
+            "format": "float"
+          },
+          "average_mobility_points_auto": {
+            "type": "number",
+            "description": "Average mobility points scored during auto.",
+            "format": "float"
+          },
+          "average_points_auto": {
+            "type": "number",
+            "description": "Average points scored during auto.",
+            "format": "float"
+          },
+          "average_points_teleop": {
+            "type": "number",
+            "description": "Average points scored during teleop.",
+            "format": "float"
+          },
+          "average_rotor_points": {
+            "type": "number",
+            "description": "Average rotor points scored.",
+            "format": "float"
+          },
+          "average_rotor_points_auto": {
+            "type": "number",
+            "description": "Average rotor points scored during auto.",
+            "format": "float"
+          },
+          "average_rotor_points_teleop": {
+            "type": "number",
+            "description": "Average rotor points scored during teleop.",
+            "format": "float"
+          },
+          "average_score": {
+            "type": "number",
+            "description": "Average score.",
+            "format": "float"
+          },
+          "average_takeoff_points_teleop": {
+            "type": "number",
+            "description": "Average takeoff points scored during teleop.",
+            "format": "float"
+          },
+          "average_win_margin": {
+            "type": "number",
+            "description": "Average margin of victory.",
+            "format": "float"
+          },
+          "average_win_score": {
+            "type": "number",
+            "description": "Average winning score.",
+            "format": "float"
+          },
+          "high_kpa": {
+            "type": "array",
+            "description": "An array with three values, kPa scored, match key from the match with the high kPa, and the name of the match",
+            "items": {
+              "type": "string"
+            }
+          },
+          "high_score": {
+            "type": "array",
+            "description": "An array with three values, high score, match key from the match with the high score, and the name of the match",
+            "items": {
+              "type": "string"
+            }
+          },
+          "kpa_achieved": {
+            "type": "array",
+            "description": "An array with three values, number of times kPa bonus achieved, number of opportunities to bonus, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "mobility_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times mobility bonus achieved, number of opportunities to bonus, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_1_engaged": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 1 engaged, number of opportunities to engage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_1_engaged_auto": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 1 engaged in auto, number of opportunities to engage in auto, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_2_engaged": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 2 engaged, number of opportunities to engage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_2_engaged_auto": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 2 engaged in auto, number of opportunities to engage in auto, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_3_engaged": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 3 engaged, number of opportunities to engage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "rotor_4_engaged": {
+            "type": "array",
+            "description": "An array with three values, number of times rotor 4 engaged, number of opportunities to engage, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "takeoff_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times takeoff was counted, number of opportunities to takeoff, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "unicorn_matches": {
+            "type": "array",
+            "description": "An array with three values, number of times a unicorn match (Win + kPa & Rotor Bonuses) occured, number of opportunities to have a unicorn match, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          }
+        },
+        "description": "Insights for FIRST STEAMWORKS qualification and elimination matches."
+      },
+      "Event_Insights_2018": {
+        "required": [
+          "auto_quest_achieved",
+          "average_boost_played",
+          "average_endgame_points",
+          "average_force_played",
+          "average_foul_score",
+          "average_points_auto",
+          "average_points_teleop",
+          "average_run_points_auto",
+          "average_scale_ownership_points",
+          "average_scale_ownership_points_auto",
+          "average_scale_ownership_points_teleop",
+          "average_score",
+          "average_switch_ownership_points",
+          "average_switch_ownership_points_auto",
+          "average_switch_ownership_points_teleop",
+          "average_vault_points",
+          "average_win_margin",
+          "average_win_score",
+          "boost_played_counts",
+          "climb_counts",
+          "face_the_boss_achieved",
+          "force_played_counts",
+          "high_score",
+          "levitate_played_counts",
+          "run_counts_auto",
+          "scale_neutral_percentage",
+          "scale_neutral_percentage_auto",
+          "scale_neutral_percentage_teleop",
+          "switch_owned_counts_auto",
+          "unicorn_matches",
+          "winning_opp_switch_denial_percentage_teleop",
+          "winning_own_switch_ownership_percentage",
+          "winning_own_switch_ownership_percentage_auto",
+          "winning_own_switch_ownership_percentage_teleop",
+          "winning_scale_ownership_percentage",
+          "winning_scale_ownership_percentage_auto",
+          "winning_scale_ownership_percentage_teleop"
+        ],
+        "type": "object",
+        "properties": {
+          "auto_quest_achieved": {
+            "type": "array",
+            "description": "An array with three values, number of times auto quest was completed, number of opportunities to complete the auto quest, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "average_boost_played": {
+            "type": "number",
+            "description": "Average number of boost power up scored (out of 3).",
+            "format": "float"
+          },
+          "average_endgame_points": {
+            "type": "number",
+            "description": "Average endgame points.",
+            "format": "float"
+          },
+          "average_force_played": {
+            "type": "number",
+            "description": "Average number of force power up scored (out of 3).",
+            "format": "float"
+          },
+          "average_foul_score": {
+            "type": "number",
+            "description": "Average foul score.",
+            "format": "float"
+          },
+          "average_points_auto": {
+            "type": "number",
+            "description": "Average points scored during auto.",
+            "format": "float"
+          },
+          "average_points_teleop": {
+            "type": "number",
+            "description": "Average points scored during teleop.",
+            "format": "float"
+          },
+          "average_run_points_auto": {
+            "type": "number",
+            "description": "Average mobility points scored during auto.",
+            "format": "float"
+          },
+          "average_scale_ownership_points": {
+            "type": "number",
+            "description": "Average scale ownership points scored.",
+            "format": "float"
+          },
+          "average_scale_ownership_points_auto": {
+            "type": "number",
+            "description": "Average scale ownership points scored during auto.",
+            "format": "float"
+          },
+          "average_scale_ownership_points_teleop": {
+            "type": "number",
+            "description": "Average scale ownership points scored during teleop.",
+            "format": "float"
+          },
+          "average_score": {
+            "type": "number",
+            "description": "Average score.",
+            "format": "float"
+          },
+          "average_switch_ownership_points": {
+            "type": "number",
+            "description": "Average switch ownership points scored.",
+            "format": "float"
+          },
+          "average_switch_ownership_points_auto": {
+            "type": "number",
+            "description": "Average switch ownership points scored during auto.",
+            "format": "float"
+          },
+          "average_switch_ownership_points_teleop": {
+            "type": "number",
+            "description": "Average switch ownership points scored during teleop.",
+            "format": "float"
+          },
+          "average_vault_points": {
+            "type": "number",
+            "description": "Average value points scored.",
+            "format": "float"
+          },
+          "average_win_margin": {
+            "type": "number",
+            "description": "Average margin of victory.",
+            "format": "float"
+          },
+          "average_win_score": {
+            "type": "number",
+            "description": "Average winning score.",
+            "format": "float"
+          },
+          "boost_played_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times a boost power up was played, number of opportunities to play a boost power up, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "climb_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times a climb occurred, number of opportunities to climb, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "face_the_boss_achieved": {
+            "type": "array",
+            "description": "An array with three values, number of times an alliance faced the boss, number of opportunities to face the boss, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "force_played_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times a force power up was played, number of opportunities to play a force power up, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "high_score": {
+            "type": "array",
+            "description": "An array with three values, high score, match key from the match with the high score, and the name of the match",
+            "items": {
+              "type": "string"
+            }
+          },
+          "levitate_played_counts": {
+            "type": "array",
+            "description": "An array with three values, number of times a levitate power up was played, number of opportunities to play a levitate power up, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "run_counts_auto": {
+            "type": "array",
+            "description": "An array with three values, number of times a team scored mobility points in auto, number of opportunities to score mobility points in auto, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "scale_neutral_percentage": {
+            "type": "number",
+            "description": "Average scale neutral percentage.",
+            "format": "float"
+          },
+          "scale_neutral_percentage_auto": {
+            "type": "number",
+            "description": "Average scale neutral percentage during auto.",
+            "format": "float"
+          },
+          "scale_neutral_percentage_teleop": {
+            "type": "number",
+            "description": "Average scale neutral percentage during teleop.",
+            "format": "float"
+          },
+          "switch_owned_counts_auto": {
+            "type": "array",
+            "description": "An array with three values, number of times a switch was owned during auto, number of opportunities to own a switch during auto, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "unicorn_matches": {
+            "type": "array",
+            "description": "An array with three values, number of times a unicorn match (Win + Auto Quest + Face the Boss) occurred, number of opportunities to have a unicorn match, and percentage.",
+            "items": {
+              "type": "number",
+              "format": "float"
+            }
+          },
+          "winning_opp_switch_denial_percentage_teleop": {
+            "type": "number",
+            "description": "Average opposing switch denail percentage for the winning alliance during teleop.",
+            "format": "float"
+          },
+          "winning_own_switch_ownership_percentage": {
+            "type": "number",
+            "description": "Average own switch ownership percentage for the winning alliance.",
+            "format": "float"
+          },
+          "winning_own_switch_ownership_percentage_auto": {
+            "type": "number",
+            "description": "Average own switch ownership percentage for the winning alliance during auto.",
+            "format": "float"
+          },
+          "winning_own_switch_ownership_percentage_teleop": {
+            "type": "number",
+            "description": "Average own switch ownership percentage for the winning alliance during teleop.",
+            "format": "float"
+          },
+          "winning_scale_ownership_percentage": {
+            "type": "number",
+            "description": "Average scale ownership percentage for the winning alliance.",
+            "format": "float"
+          },
+          "winning_scale_ownership_percentage_auto": {
+            "type": "number",
+            "description": "Average scale ownership percentage for the winning alliance during auto.",
+            "format": "float"
+          },
+          "winning_scale_ownership_percentage_teleop": {
+            "type": "number",
+            "description": "Average scale ownership percentage for the winning alliance during teleop.",
+            "format": "float"
+          }
+        },
+        "description": "Insights for FIRST Power Up qualification and elimination matches."
+      },
+      "Event_OPRs": {
+        "type": "object",
+        "properties": {
+          "oprs": {
+            "type": "object",
+            "additionalProperties": {
+              "type": "number",
+              "description": "OPR for team.",
+              "format": "float"
+            },
+            "description": "A key-value pair with team key (eg `frc254`) as key and OPR as value."
+          },
+          "dprs": {
+            "type": "object",
+            "additionalProperties": {
+              "type": "number",
+              "description": "DPR for team.",
+              "format": "float"
+            },
+            "description": "A key-value pair with team key (eg `frc254`) as key and DPR as value."
+          },
+          "ccwms": {
+            "type": "object",
+            "additionalProperties": {
+              "type": "number",
+              "description": "CCWM for team.",
+              "format": "float"
+            },
+            "description": "A key-value pair with team key (eg `frc254`) as key and CCWM as value."
+          }
+        },
+        "description": "OPR, DPR, and CCWM for teams at the event."
+      },
+      "Event_Predictions": {
+        "type": "object",
+        "description": "JSON Object containing prediction information for the event. Contains year-specific information and is subject to change."
+      },
+      "Match_Simple": {
+        "required": [
+          "comp_level",
+          "event_key",
+          "key",
+          "match_number",
+          "set_number"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA match key with the format `yyyy[EVENT_CODE]_[COMP_LEVEL]m[MATCH_NUMBER]`, where `yyyy` is the year, and `EVENT_CODE` is the event code of the event, `COMP_LEVEL` is (qm, ef, qf, sf, f), and `MATCH_NUMBER` is the match number in the competition level. A set number may append the competition level if more than one match in required per set."
+          },
+          "comp_level": {
+            "type": "string",
+            "description": "The competition level the match was played at.",
+            "enum": [
+              "qm",
+              "ef",
+              "qf",
+              "sf",
+              "f"
+            ]
+          },
+          "set_number": {
+            "type": "integer",
+            "description": "The set number in a series of matches where more than one match is required in the match series."
+          },
+          "match_number": {
+            "type": "integer",
+            "description": "The match number of the match in the competition level."
+          },
+          "alliances": {
+            "type": "object",
+            "properties": {
+              "red": {
+                "$ref": "#/components/schemas/Match_alliance"
+              },
+              "blue": {
+                "$ref": "#/components/schemas/Match_alliance"
+              }
+            },
+            "description": "A list of alliances, the teams on the alliances, and their score."
+          },
+          "winning_alliance": {
+            "type": "string",
+            "description": "The color (red/blue) of the winning alliance. Will contain an empty string in the event of no winner, or a tie.",
+            "enum": [
+              "red",
+              "blue",
+              ""
+            ]
+          },
+          "event_key": {
+            "type": "string",
+            "description": "Event key of the event the match was played at."
+          },
+          "time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of the scheduled match time, as taken from the published schedule.",
+            "format": "int64"
+          },
+          "predicted_time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of the TBA predicted match start time.",
+            "format": "int64"
+          },
+          "actual_time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of actual match start time.",
+            "format": "int64"
+          }
+        }
+      },
+      "Match": {
+        "required": [
+          "comp_level",
+          "event_key",
+          "key",
+          "match_number",
+          "set_number"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA match key with the format `yyyy[EVENT_CODE]_[COMP_LEVEL]m[MATCH_NUMBER]`, where `yyyy` is the year, and `EVENT_CODE` is the event code of the event, `COMP_LEVEL` is (qm, ef, qf, sf, f), and `MATCH_NUMBER` is the match number in the competition level. A set number may be appended to the competition level if more than one match in required per set."
+          },
+          "comp_level": {
+            "type": "string",
+            "description": "The competition level the match was played at.",
+            "enum": [
+              "qm",
+              "ef",
+              "qf",
+              "sf",
+              "f"
+            ]
+          },
+          "set_number": {
+            "type": "integer",
+            "description": "The set number in a series of matches where more than one match is required in the match series."
+          },
+          "match_number": {
+            "type": "integer",
+            "description": "The match number of the match in the competition level."
+          },
+          "alliances": {
+            "type": "object",
+            "properties": {
+              "red": {
+                "$ref": "#/components/schemas/Match_alliance"
+              },
+              "blue": {
+                "$ref": "#/components/schemas/Match_alliance"
+              }
+            },
+            "description": "A list of alliances, the teams on the alliances, and their score."
+          },
+          "winning_alliance": {
+            "type": "string",
+            "description": "The color (red/blue) of the winning alliance. Will contain an empty string in the event of no winner, or a tie.",
+            "enum": [
+              "red",
+              "blue",
+              ""
+            ]
+          },
+          "event_key": {
+            "type": "string",
+            "description": "Event key of the event the match was played at."
+          },
+          "time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of the scheduled match time, as taken from the published schedule.",
+            "format": "int64"
+          },
+          "actual_time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of actual match start time.",
+            "format": "int64"
+          },
+          "predicted_time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) of the TBA predicted match start time.",
+            "format": "int64"
+          },
+          "post_result_time": {
+            "type": "integer",
+            "description": "UNIX timestamp (seconds since 1-Jan-1970 00:00:00) when the match result was posted.",
+            "format": "int64"
+          },
+          "score_breakdown": {
+            "type": "object",
+            "properties": {},
+            "description": "Score breakdown for auto, teleop, etc. points. Varies from year to year. May be null."
+          },
+          "videos": {
+            "type": "array",
+            "description": "Array of video objects associated with this match.",
+            "items": {
+              "type": "object",
+              "properties": {
+                "type": {
+                  "type": "string",
+                  "description": "Can be one of 'youtube' or 'tba'"
+                },
+                "key": {
+                  "type": "string",
+                  "description": "Unique key representing this video"
+                }
+              }
+            }
+          }
+        }
+      },
+      "Match_alliance": {
+        "required": [
+          "score",
+          "team_keys"
+        ],
+        "type": "object",
+        "properties": {
+          "score": {
+            "type": "integer",
+            "description": "Score for this alliance. Will be null or -1 for an unplayed match."
+          },
+          "team_keys": {
+            "type": "array",
+            "items": {
+              "type": "string",
+              "description": "TBA Team keys (eg `frc254`) for teams on this alliance."
+            }
+          },
+          "surrogate_team_keys": {
+            "type": "array",
+            "description": "TBA team keys (eg `frc254`) of any teams playing as a surrogate.",
+            "items": {
+              "type": "string",
+              "description": "Team key of a surrogate team."
+            }
+          },
+          "dq_team_keys": {
+            "type": "array",
+            "description": "TBA team keys (eg `frc254`) of any disqualified teams.",
+            "items": {
+              "type": "string",
+              "description": "Team key of a disqualified team."
+            }
+          }
+        }
+      },
+      "Zebra": {
+        "required": [
+          "key",
+          "times",
+          "alliances"
+        ],
+        "type": "object",
+        "properties": {
+          "key": {
+            "type": "string",
+            "description": "TBA match key with the format `yyyy[EVENT_CODE]_[COMP_LEVEL]m[MATCH_NUMBER]`, where `yyyy` is the year, and `EVENT_CODE` is the event code of the event, `COMP_LEVEL` is (qm, ef, qf, sf, f), and `MATCH_NUMBER` is the match number in the competition level. A set number may be appended to the competition level if more than one match in required per set."
+          },
+          "times": {
+            "type": "array",
+            "description": "A list of relative timestamps for each data point. Each timestamp will correspond to the X and Y value at the same index in a team xs and ys arrays. `times`, all teams `xs` and all teams `ys` are guarenteed to be the same length.",
+            "items": {
+              "type": "number",
+              "format": "double",
+              "example": [
+                0.0,
+                0.1,
+                0.2
+              ]
+            }
+          },
+          "alliances": {
+            "type": "object",
+            "properties": {
+              "red": {
+                "type": "array",
+                "description": "Zebra MotionWorks data for teams on the red alliance",
+                "items": {
+                  "$ref": "#/components/schemas/Zebra_team"
+                }
+              },
+              "blue": {
+                "type": "array",
+                "description": "Zebra data for teams on the blue alliance",
+                "items": {
+                  "$ref": "#/components/schemas/Zebra_team"
+                }
+              }
+            }
+          }
+        }
+      },
+      "Zebra_team": {
+        "required": [
+          "team_key",
+          "xs",
+          "ys"
+        ],
+        "type": "object",
+        "properties": {
+          "team_key": {
+            "type": "string",
+            "description": "The TBA team key for the Zebra MotionWorks data.",
+            "example": "frc7332"
+          },
+          "xs": {
+            "type": "array",
+            "description": "A list containing doubles and nulls representing a teams X position in feet at the corresponding timestamp. A null value represents no tracking data for a given timestamp.",
+            "items": {
+              "type": "number",
+              "format": "double",
+              "example": [
+                2.73,
+                2.70,
+                null
+              ]
+            }
+          },
+          "ys": {
+            "type": "array",
+            "description": "A list containing doubles and nulls representing a teams Y position in feet at the corresponding timestamp. A null value represents no tracking data for a given timestamp.",
+            "items": {
+              "type": "number",
+              "format": "double",
+              "example": [
+                2.73,
+                2.70,
+                null
+              ]
+            }
+          }
+        }
+      },
+      "Match_Score_Breakdown_2015": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2015_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2015_Alliance"
+          },
+          "coopertition": {
+            "type": "string",
+            "enum": [
+              "None",
+              "Unknown",
+              "Stack"
+            ]
+          },
+          "coopertition_points": {
+            "type": "integer"
+          }
+        },
+        "description": "See the 2015 FMS API documentation for a description of each value"
+      },
+      "Match_Score_Breakdown_2015_Alliance": {
+        "type": "object",
+        "properties": {
+          "auto_points": {
+            "type": "integer"
+          },
+          "teleop_points": {
+            "type": "integer"
+          },
+          "container_points": {
+            "type": "integer"
+          },
+          "tote_points": {
+            "type": "integer"
+          },
+          "litter_points": {
+            "type": "integer"
+          },
+          "foul_points": {
+            "type": "integer"
+          },
+          "adjust_points": {
+            "type": "integer"
+          },
+          "total_points": {
+            "type": "integer"
+          },
+          "foul_count": {
+            "type": "integer"
+          },
+          "tote_count_far": {
+            "type": "integer"
+          },
+          "tote_count_near": {
+            "type": "integer"
+          },
+          "tote_set": {
+            "type": "boolean"
+          },
+          "tote_stack": {
+            "type": "boolean"
+          },
+          "container_count_level1": {
+            "type": "integer"
+          },
+          "container_count_level2": {
+            "type": "integer"
+          },
+          "container_count_level3": {
+            "type": "integer"
+          },
+          "container_count_level4": {
+            "type": "integer"
+          },
+          "container_count_level5": {
+            "type": "integer"
+          },
+          "container_count_level6": {
+            "type": "integer"
+          },
+          "container_set": {
+            "type": "boolean"
+          },
+          "litter_count_container": {
+            "type": "integer"
+          },
+          "litter_count_landfill": {
+            "type": "integer"
+          },
+          "litter_count_unprocessed": {
+            "type": "integer"
+          },
+          "robot_set": {
+            "type": "boolean"
+          }
+        }
+      },
+      "Match_Score_Breakdown_2016": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2016_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2016_Alliance"
+          }
+        },
+        "description": "See the 2016 FMS API documentation for a description of each value."
+      },
+      "Match_Score_Breakdown_2016_Alliance": {
+        "type": "object",
+        "properties": {
+          "autoPoints": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "breachPoints": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "capturePoints": {
+            "type": "integer"
+          },
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "totalPoints": {
+            "type": "integer"
+          },
+          "robot1Auto": {
+            "type": "string",
+            "enum": [
+              "Crossed",
+              "Reached",
+              "None"
+            ]
+          },
+          "robot2Auto": {
+            "type": "string",
+            "enum": [
+              "Crossed",
+              "Reached",
+              "None"
+            ]
+          },
+          "robot3Auto": {
+            "type": "string",
+            "enum": [
+              "Crossed",
+              "Reached",
+              "None"
+            ]
+          },
+          "autoReachPoints": {
+            "type": "integer"
+          },
+          "autoCrossingPoints": {
+            "type": "integer"
+          },
+          "autoBouldersLow": {
+            "type": "integer"
+          },
+          "autoBouldersHigh": {
+            "type": "integer"
+          },
+          "autoBoulderPoints": {
+            "type": "integer"
+          },
+          "teleopCrossingPoints": {
+            "type": "integer"
+          },
+          "teleopBouldersLow": {
+            "type": "integer"
+          },
+          "teleopBouldersHigh": {
+            "type": "integer"
+          },
+          "teleopBoulderPoints": {
+            "type": "integer"
+          },
+          "teleopDefensesBreached": {
+            "type": "boolean"
+          },
+          "teleopChallengePoints": {
+            "type": "integer"
+          },
+          "teleopScalePoints": {
+            "type": "integer"
+          },
+          "teleopTowerCaptured": {
+            "type": "integer"
+          },
+          "towerFaceA": {
+            "type": "string"
+          },
+          "towerFaceB": {
+            "type": "string"
+          },
+          "towerFaceC": {
+            "type": "string"
+          },
+          "towerEndStrength": {
+            "type": "integer"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "position2": {
+            "type": "string"
+          },
+          "position3": {
+            "type": "string"
+          },
+          "position4": {
+            "type": "string"
+          },
+          "position5": {
+            "type": "string"
+          },
+          "position1crossings": {
+            "type": "integer"
+          },
+          "position2crossings": {
+            "type": "integer"
+          },
+          "position3crossings": {
+            "type": "integer"
+          },
+          "position4crossings": {
+            "type": "integer"
+          },
+          "position5crossings": {
+            "type": "integer"
+          }
+        }
+      },
+      "Match_Score_Breakdown_2017": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2017_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2017_Alliance"
+          }
+        },
+        "description": "See the 2017 FMS API documentation for a description of each value."
+      },
+      "Match_Score_Breakdown_2017_Alliance": {
+        "type": "object",
+        "properties": {
+          "autoPoints": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "totalPoints": {
+            "type": "integer"
+          },
+          "robot1Auto": {
+            "type": "string",
+            "enum": [
+              "Unknown",
+              "Mobility",
+              "None"
+            ]
+          },
+          "robot2Auto": {
+            "type": "string",
+            "enum": [
+              "Unknown",
+              "Mobility",
+              "None"
+            ]
+          },
+          "robot3Auto": {
+            "type": "string",
+            "enum": [
+              "Unknown",
+              "Mobility",
+              "None"
+            ]
+          },
+          "rotor1Auto": {
+            "type": "boolean"
+          },
+          "rotor2Auto": {
+            "type": "boolean"
+          },
+          "autoFuelLow": {
+            "type": "integer"
+          },
+          "autoFuelHigh": {
+            "type": "integer"
+          },
+          "autoMobilityPoints": {
+            "type": "integer"
+          },
+          "autoRotorPoints": {
+            "type": "integer"
+          },
+          "autoFuelPoints": {
+            "type": "integer"
+          },
+          "teleopFuelPoints": {
+            "type": "integer"
+          },
+          "teleopFuelLow": {
+            "type": "integer"
+          },
+          "teleopFuelHigh": {
+            "type": "integer"
+          },
+          "teleopRotorPoints": {
+            "type": "integer"
+          },
+          "kPaRankingPointAchieved": {
+            "type": "boolean"
+          },
+          "teleopTakeoffPoints": {
+            "type": "integer"
+          },
+          "kPaBonusPoints": {
+            "type": "integer"
+          },
+          "rotorBonusPoints": {
+            "type": "integer"
+          },
+          "rotor1Engaged": {
+            "type": "boolean"
+          },
+          "rotor2Engaged": {
+            "type": "boolean"
+          },
+          "rotor3Engaged": {
+            "type": "boolean"
+          },
+          "rotor4Engaged": {
+            "type": "boolean"
+          },
+          "rotorRankingPointAchieved": {
+            "type": "boolean"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "touchpadNear": {
+            "type": "string"
+          },
+          "touchpadMiddle": {
+            "type": "string"
+          },
+          "touchpadFar": {
+            "type": "string"
+          }
+        }
+      },
+      "Match_Score_Breakdown_2018": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2018_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2018_Alliance"
+          }
+        },
+        "description": "See the 2018 FMS API documentation for a description of each value. https://frcevents2.docs.apiary.io/#/reference/match-results/score-details"
+      },
+      "Match_Score_Breakdown_2018_Alliance": {
+        "type": "object",
+        "properties": {
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "autoOwnershipPoints": {
+            "type": "integer"
+          },
+          "autoPoints": {
+            "type": "integer"
+          },
+          "autoQuestRankingPoint": {
+            "type": "boolean"
+          },
+          "autoRobot1": {
+            "type": "string"
+          },
+          "autoRobot2": {
+            "type": "string"
+          },
+          "autoRobot3": {
+            "type": "string"
+          },
+          "autoRunPoints": {
+            "type": "integer"
+          },
+          "autoScaleOwnershipSec": {
+            "type": "integer"
+          },
+          "autoSwitchAtZero": {
+            "type": "boolean"
+          },
+          "autoSwitchOwnershipSec": {
+            "type": "integer"
+          },
+          "endgamePoints": {
+            "type": "integer"
+          },
+          "endgameRobot1": {
+            "type": "string"
+          },
+          "endgameRobot2": {
+            "type": "string"
+          },
+          "endgameRobot3": {
+            "type": "string"
+          },
+          "faceTheBossRankingPoint": {
+            "type": "boolean"
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "rp": {
+            "type": "integer"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "teleopOwnershipPoints": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "teleopScaleBoostSec": {
+            "type": "integer"
+          },
+          "teleopScaleForceSec": {
+            "type": "integer"
+          },
+          "teleopScaleOwnershipSec": {
+            "type": "integer"
+          },
+          "teleopSwitchBoostSec": {
+            "type": "integer"
+          },
+          "teleopSwitchForceSec": {
+            "type": "integer"
+          },
+          "teleopSwitchOwnershipSec": {
+            "type": "integer"
+          },
+          "totalPoints": {
+            "type": "integer"
+          },
+          "vaultBoostPlayed": {
+            "type": "integer"
+          },
+          "vaultBoostTotal": {
+            "type": "integer"
+          },
+          "vaultForcePlayed": {
+            "type": "integer"
+          },
+          "vaultForceTotal": {
+            "type": "integer"
+          },
+          "vaultLevitatePlayed": {
+            "type": "integer"
+          },
+          "vaultLevitateTotal": {
+            "type": "integer"
+          },
+          "vaultPoints": {
+            "type": "integer"
+          },
+          "tba_gameData": {
+            "type": "string",
+            "description": "Unofficial TBA-computed value of the FMS provided GameData given to the alliance teams at the start of the match. 3 Character String containing `L` and `R` only. The first character represents the near switch, the 2nd the scale, and the 3rd the far, opposing, switch from the alliance's perspective. An `L` in a position indicates the platform on the left will be lit for the alliance while an `R` will indicate the right platform will be lit for the alliance. See also [WPI Screen Steps](https://wpilib.screenstepslive.com/s/currentCS/m/getting_started/l/826278-2018-game-data-details)."
+          }
+        }
+      },
+      "Match_Timeseries_2018": {
+        "type": "object",
+        "properties": {
+          "event_key": {
+            "type": "string",
+            "description": "TBA event key with the format yyyy[EVENT_CODE], where yyyy is the year, and EVENT_CODE is the event code of the event."
+          },
+          "match_id": {
+            "type": "string",
+            "description": "Match ID consisting of the level, match number, and set number, eg `qm45` or `f1m1`."
+          },
+          "mode": {
+            "type": "string",
+            "description": "Current mode of play, can be `pre_match`, `auto`, `telop`, or `post_match`."
+          },
+          "play": {
+            "type": "integer"
+          },
+          "time_remaining": {
+            "type": "integer",
+            "description": "Amount of time remaining in the match, only valid during `auto` and `teleop` modes."
+          },
+          "blue_auto_quest": {
+            "type": "integer",
+            "description": "1 if the blue alliance is credited with the AUTO QUEST, 0 if not."
+          },
+          "blue_boost_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the BOOST section of the blue alliance VAULT."
+          },
+          "blue_boost_played": {
+            "type": "integer",
+            "description": "Returns 1 if the blue alliance BOOST was played, or 0 if not played."
+          },
+          "blue_current_powerup": {
+            "type": "string",
+            "description": "Name of the current blue alliance POWER UP being played, or `null`."
+          },
+          "blue_face_the_boss": {
+            "type": "integer",
+            "description": "1 if the blue alliance is credited with FACING THE BOSS, 0 if not."
+          },
+          "blue_force_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the FORCE section of the blue alliance VAULT."
+          },
+          "blue_force_played": {
+            "type": "integer",
+            "description": "Returns 1 if the blue alliance FORCE was played, or 0 if not played."
+          },
+          "blue_levitate_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the LEVITATE section of the blue alliance VAULT."
+          },
+          "blue_levitate_played": {
+            "type": "integer",
+            "description": "Returns 1 if the blue alliance LEVITATE was played, or 0 if not played."
+          },
+          "blue_powerup_time_remaining": {
+            "type": "string",
+            "description": "Number of seconds remaining in the blue alliance POWER UP time, or 0 if none is active."
+          },
+          "blue_scale_owned": {
+            "type": "integer",
+            "description": "1 if the blue alliance owns the SCALE, 0 if not."
+          },
+          "blue_score": {
+            "type": "integer",
+            "description": "Current score for the blue alliance."
+          },
+          "blue_switch_owned": {
+            "type": "integer",
+            "description": "1 if the blue alliance owns their SWITCH, 0 if not."
+          },
+          "red_auto_quest": {
+            "type": "integer",
+            "description": "1 if the red alliance is credited with the AUTO QUEST, 0 if not."
+          },
+          "red_boost_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the BOOST section of the red alliance VAULT."
+          },
+          "red_boost_played": {
+            "type": "integer",
+            "description": "Returns 1 if the red alliance BOOST was played, or 0 if not played."
+          },
+          "red_current_powerup": {
+            "type": "string",
+            "description": "Name of the current red alliance POWER UP being played, or `null`."
+          },
+          "red_face_the_boss": {
+            "type": "integer",
+            "description": "1 if the red alliance is credited with FACING THE BOSS, 0 if not."
+          },
+          "red_force_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the FORCE section of the red alliance VAULT."
+          },
+          "red_force_played": {
+            "type": "integer",
+            "description": "Returns 1 if the red alliance FORCE was played, or 0 if not played."
+          },
+          "red_levitate_count": {
+            "type": "integer",
+            "description": "Number of POWER CUBES in the LEVITATE section of the red alliance VAULT."
+          },
+          "red_levitate_played": {
+            "type": "integer",
+            "description": "Returns 1 if the red alliance LEVITATE was played, or 0 if not played."
+          },
+          "red_powerup_time_remaining": {
+            "type": "string",
+            "description": "Number of seconds remaining in the red alliance POWER UP time, or 0 if none is active."
+          },
+          "red_scale_owned": {
+            "type": "integer",
+            "description": "1 if the red alliance owns the SCALE, 0 if not."
+          },
+          "red_score": {
+            "type": "integer",
+            "description": "Current score for the red alliance."
+          },
+          "red_switch_owned": {
+            "type": "integer",
+            "description": "1 if the red alliance owns their SWITCH, 0 if not."
+          }
+        },
+        "description": "Timeseries data for the 2018 game *FIRST* POWER UP.\n*WARNING:* This is *not* official data, and is subject to a significant possibility of error, or missing data. Do not rely on this data for any purpose. In fact, pretend we made it up.\n*WARNING:* This model is currently under active development and may change at any time, including in breaking ways."
+      },
+      "Match_Score_Breakdown_2019": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2019_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2019_Alliance"
+          }
+        },
+        "description": "See the 2019 FMS API documentation for a description of each value. https://frcevents2.docs.apiary.io/#/reference/match-results/score-details"
+      },
+      "Match_Score_Breakdown_2019_Alliance": {
+        "type": "object",
+        "properties": {
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "autoPoints": {
+            "type": "integer"
+          },
+          "bay1": {
+            "type": "string"
+          },
+          "bay2": {
+            "type": "string"
+          },
+          "bay3": {
+            "type": "string"
+          },
+          "bay4": {
+            "type": "string"
+          },
+          "bay5": {
+            "type": "string"
+          },
+          "bay6": {
+            "type": "string"
+          },
+          "bay7": {
+            "type": "string"
+          },
+          "bay8": {
+            "type": "string"
+          },
+          "cargoPoints": {
+            "type": "integer"
+          },
+          "completeRocketRankingPoint": {
+            "type": "boolean"
+          },
+          "completedRocketFar": {
+            "type": "boolean"
+          },
+          "completedRocketNear": {
+            "type": "boolean"
+          },
+          "endgameRobot1": {
+            "type": "string"
+          },
+          "endgameRobot2": {
+            "type": "string"
+          },
+          "endgameRobot3": {
+            "type": "string"
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "habClimbPoints": {
+            "type": "integer"
+          },
+          "habDockingRankingPoint": {
+            "type": "boolean"
+          },
+          "habLineRobot1": {
+            "type": "string"
+          },
+          "habLineRobot2": {
+            "type": "string"
+          },
+          "habLineRobot3": {
+            "type": "string"
+          },
+          "hatchPanelPoints": {
+            "type": "integer"
+          },
+          "lowLeftRocketFar": {
+            "type": "string"
+          },
+          "lowLeftRocketNear": {
+            "type": "string"
+          },
+          "lowRightRocketFar": {
+            "type": "string"
+          },
+          "lowRightRocketNear": {
+            "type": "string"
+          },
+          "midLeftRocketFar": {
+            "type": "string"
+          },
+          "midLeftRocketNear": {
+            "type": "string"
+          },
+          "midRightRocketFar": {
+            "type": "string"
+          },
+          "midRightRocketNear": {
+            "type": "string"
+          },
+          "preMatchBay1": {
+            "type": "string"
+          },
+          "preMatchBay2": {
+            "type": "string"
+          },
+          "preMatchBay3": {
+            "type": "string"
+          },
+          "preMatchBay6": {
+            "type": "string"
+          },
+          "preMatchBay7": {
+            "type": "string"
+          },
+          "preMatchBay8": {
+            "type": "string"
+          },
+          "preMatchLevelRobot1": {
+            "type": "string"
+          },
+          "preMatchLevelRobot2": {
+            "type": "string"
+          },
+          "preMatchLevelRobot3": {
+            "type": "string"
+          },
+          "rp": {
+            "type": "integer"
+          },
+          "sandStormBonusPoints": {
+            "type": "integer"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "topLeftRocketFar": {
+            "type": "string"
+          },
+          "topLeftRocketNear": {
+            "type": "string"
+          },
+          "topRightRocketFar": {
+            "type": "string"
+          },
+          "topRightRocketNear": {
+            "type": "string"
+          },
+          "totalPoints": {
+            "type": "integer"
+          }
+        }
+      },
+      "Match_Score_Breakdown_2020": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2020_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2020_Alliance"
+          }
+        },
+        "description": "See the 2020 FMS API documentation for a description of each value. https://frcevents2.docs.apiary.io/#/reference/match-results/score-details"
+      },
+      "Match_Score_Breakdown_2020_Alliance": {
+        "type": "object",
+        "properties": {
+          "initLineRobot1": {
+            "type": "string"
+          },
+          "endgameRobot1": {
+            "type": "string"
+          },
+          "initLineRobot2": {
+            "type": "string"
+          },
+          "endgameRobot2": {
+            "type": "string"
+          },
+          "initLineRobot3": {
+            "type": "string"
+          },
+          "endgameRobot3": {
+            "type": "string"
+          },
+          "autoCellsBottom": {
+            "type": "integer"
+          },
+          "autoCellsOuter": {
+            "type": "integer"
+          },
+          "autoCellsInner": {
+            "type": "integer"
+          },
+          "teleopCellsBottom": {
+            "type": "integer"
+          },
+          "teleopCellsOuter": {
+            "type": "integer"
+          },
+          "teleopCellsInner": {
+            "type": "integer"
+          },
+          "stage1Activated": {
+            "type": "boolean"
+          },
+          "stage2Activated": {
+            "type": "boolean"
+          },
+          "stage3Activated": {
+            "type": "boolean"
+          },
+          "stage3TargetColor": {
+            "type": "string"
+          },
+          "endgameRungIsLevel": {
+            "type": "string"
+          },
+          "autoInitLinePoints": {
+            "type": "integer"
+          },
+          "autoCellPoints": {
+            "type": "integer"
+          },
+          "autoPoints": {
+            "type": "integer"
+          },
+          "teleopCellPoints": {
+            "type": "integer"
+          },
+          "controlPanelPoints": {
+            "type": "integer"
+          },
+          "endgamePoints": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "shieldOperationalRankingPoint": {
+            "type": "boolean"
+          },
+          "shieldEnergizedRankingPoint": {
+            "type": "boolean"
+          },
+          "tba_shieldEnergizedRankingPointFromFoul": {
+            "type": "boolean",
+            "description": "Unofficial TBA-computed value that indicates whether the shieldEnergizedRankingPoint was earned normally or awarded due to a foul."
+          },
+          "tba_numRobotsHanging": {
+            "type": "integer",
+            "description": "Unofficial TBA-computed value that counts the number of robots who were hanging at the end of the match."
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "rp": {
+            "type": "integer"
+          },
+          "totalPoints": {
+            "type": "integer"
+          }
+        }
+      },
+      "Match_Score_Breakdown_2022": {
+        "type": "object",
+        "properties": {
+          "blue": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2022_Alliance"
+          },
+          "red": {
+            "$ref": "#/components/schemas/Match_Score_Breakdown_2022_Alliance"
+          }
+        },
+        "description": "See the 2022 FMS API documentation for a description of each value. https://frc-api-docs.firstinspires.org"
+      },
+      "Match_Score_Breakdown_2022_Alliance": {
+        "type": "object",
+        "properties": {
+          "taxiRobot1": {
+            "type": "string",
+            "enum": [
+              "Yes",
+              "No"
+            ]
+          },
+          "endgameRobot1": {
+            "type": "string",
+            "enum": [
+              "Traversal",
+              "High",
+              "Mid",
+              "Low",
+              "None"
+            ]
+          },
+          "taxiRobot2": {
+            "type": "string",
+            "enum": [
+              "Yes",
+              "No"
+            ]
+          },
+          "endgameRobot2": {
+            "type": "string",
+            "enum": [
+              "Traversal",
+              "High",
+              "Mid",
+              "Low",
+              "None"
+            ]
+          },
+          "taxiRobot3": {
+            "type": "string",
+            "enum": [
+              "Yes",
+              "No"
+            ]
+          },
+          "endgameRobot3": {
+            "type": "string",
+            "enum": [
+              "Traversal",
+              "High",
+              "Mid",
+              "Low",
+              "None"
+            ]
+          },
+          "autoCargoLowerNear": {
+            "type": "integer"
+          },
+          "autoCargoLowerFar": {
+            "type": "integer"
+          },
+          "autoCargoLowerBlue": {
+            "type": "integer"
+          },
+          "autoCargoLowerRed": {
+            "type": "integer"
+          },
+          "autoCargoUpperNear": {
+            "type": "integer"
+          },
+          "autoCargoUpperFar": {
+            "type": "integer"
+          },
+          "autoCargoUpperBlue": {
+            "type": "integer"
+          },
+          "autoCargoUpperRed": {
+            "type": "integer"
+          },
+          "autoCargoTotal": {
+            "type": "integer"
+          },
+          "teleopCargoLowerNear": {
+            "type": "integer"
+          },
+          "teleopCargoLowerFar": {
+            "type": "integer"
+          },
+          "teleopCargoLowerBlue": {
+            "type": "integer"
+          },
+          "teleopCargoLowerRed": {
+            "type": "integer"
+          },
+          "teleopCargoUpperNear": {
+            "type": "integer"
+          },
+          "teleopCargoUpperFar": {
+            "type": "integer"
+          },
+          "teleopCargoUpperBlue": {
+            "type": "integer"
+          },
+          "teleopCargoUpperRed": {
+            "type": "integer"
+          },
+          "teleopCargoTotal": {
+            "type": "integer"
+          },
+          "matchCargoTotal": {
+            "type": "integer"
+          },
+          "autoTaxiPoints": {
+            "type": "integer"
+          },
+          "autoCargoPoints": {
+            "type": "integer"
+          },
+          "autoPoints": {
+            "type": "integer"
+          },
+          "quintetAchieved": {
+            "type": "boolean"
+          },
+          "teleopCargoPoints": {
+            "type": "integer"
+          },
+          "endgamePoints": {
+            "type": "integer"
+          },
+          "teleopPoints": {
+            "type": "integer"
+          },
+          "cargoBonusRankingPoint": {
+            "type": "boolean"
+          },
+          "hangarBonusRankingPoint": {
+            "type": "boolean"
+          },
+          "foulCount": {
+            "type": "integer"
+          },
+          "techFoulCount": {
+            "type": "integer"
+          },
+          "adjustPoints": {
+            "type": "integer"
+          },
+          "foulPoints": {
+            "type": "integer"
+          },
+          "rp": {
+            "type": "integer"
+          },
+          "totalPoints": {
+            "type": "integer"
+          }
+        }
+      },
+      "Media": {
+        "required": [
+          "type",
+          "foreign_key"
+        ],
+        "type": "object",
+        "properties": {
+          "type": {
+            "type": "string",
+            "description": "String type of the media element.",
+            "enum": [
+              "youtube",
+              "cdphotothread",
+              "imgur",
+              "facebook-profile",
+              "youtube-channel",
+              "twitter-profile",
+              "github-profile",
+              "instagram-profile",
+              "periscope-profile",
+              "grabcad",
+              "instagram-image",
+              "external-link",
+              "avatar"
+            ]
+          },
+          "foreign_key": {
+            "type": "string",
+            "description": "The key used to identify this media on the media site."
+          },
+          "details": {
+            "type": "object",
+            "properties": {},
+            "description": "If required, a JSON dict of additional media information."
+          },
+          "preferred": {
+            "type": "boolean",
+            "description": "True if the media is of high quality."
+          },
+          "direct_url": {
+            "type": "string",
+            "description": "Direct URL to the media."
+          },
+          "view_url": {
+            "type": "string",
+            "description": "The URL that leads to the full web page for the media, if one exists."
+          }
+        },
+        "description": "The `Media` object contains a reference for most any media associated with a team or event on TBA."
+      },
+      "Elimination_Alliance": {
+        "required": [
+          "picks"
+        ],
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Alliance name, may be null."
+          },
+          "backup": {
+            "type": "object",
+            "properties": {
+              "in": {
+                "type": "string",
+                "description": "Team key that was called in as the backup."
+              },
+              "out": {
+                "type": "string",
+                "description": "Team key that was replaced by the backup team."
+              }
+            },
+            "description": "Backup team called in, may be null."
+          },
+          "declines": {
+            "type": "array",
+            "description": "List of teams that declined the alliance.",
+            "items": {
+              "type": "string",
+              "description": "Team key that declined the alliance."
+            }
+          },
+          "picks": {
+            "type": "array",
+            "description": "List of team keys picked for the alliance. First pick is captain.",
+            "items": {
+              "type": "string",
+              "description": "Team key picked for the alliance."
+            }
+          },
+          "status": {
+            "type": "object",
+            "properties": {
+              "playoff_average": {
+                "type": "number",
+                "format": "double"
+              },
+              "level": {
+                "type": "string"
+              },
+              "record": {
+                "$ref": "#/components/schemas/WLT_Record"
+              },
+              "current_level_record": {
+                "$ref": "#/components/schemas/WLT_Record"
+              },
+              "status": {
+                "type": "string"
+              }
+            }
+          }
+        }
+      },
+      "Award": {
+        "required": [
+          "award_type",
+          "event_key",
+          "name",
+          "recipient_list",
+          "year"
+        ],
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "The name of the award as provided by FIRST. May vary for the same award type."
+          },
+          "award_type": {
+            "type": "integer",
+            "description": "Type of award given. See https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/award_type.py#L6"
+          },
+          "event_key": {
+            "type": "string",
+            "description": "The event_key of the event the award was won at."
+          },
+          "recipient_list": {
+            "type": "array",
+            "description": "A list of recipients of the award at the event. May have either a team_key or an awardee, both, or neither (in the case the award wasn't awarded at the event).",
+            "items": {
+              "$ref": "#/components/schemas/Award_Recipient"
+            }
+          },
+          "year": {
+            "type": "integer",
+            "description": "The year this award was won."
+          }
+        }
+      },
+      "Award_Recipient": {
+        "type": "object",
+        "properties": {
+          "team_key": {
+            "type": "string",
+            "description": "The TBA team key for the team that was given the award. May be null."
+          },
+          "awardee": {
+            "type": "string",
+            "description": "The name of the individual given the award. May be null."
+          }
+        },
+        "description": "An `Award_Recipient` object represents the team and/or person who received an award at an event."
+      },
+      "District_List": {
+        "required": [
+          "abbreviation",
+          "display_name",
+          "key",
+          "year"
+        ],
+        "type": "object",
+        "properties": {
+          "abbreviation": {
+            "type": "string",
+            "description": "The short identifier for the district."
+          },
+          "display_name": {
+            "type": "string",
+            "description": "The long name for the district."
+          },
+          "key": {
+            "type": "string",
+            "description": "Key for this district, e.g. `2016ne`."
+          },
+          "year": {
+            "type": "integer",
+            "description": "Year this district participated."
+          }
+        }
+      },
+      "District_Ranking": {
+        "required": [
+          "point_total",
+          "rank",
+          "team_key"
+        ],
+        "type": "object",
+        "properties": {
+          "team_key": {
+            "type": "string",
+            "description": "TBA team key for the team."
+          },
+          "rank": {
+            "type": "integer",
+            "description": "Numerical rank of the team, 1 being top rank."
+          },
+          "rookie_bonus": {
+            "type": "integer",
+            "description": "Any points added to a team as a result of the rookie bonus."
+          },
+          "point_total": {
+            "type": "integer",
+            "description": "Total district points for the team."
+          },
+          "event_points": {
+            "type": "array",
+            "description": "List of events that contributed to the point total for the team.",
+            "items": {
+              "required": [
+                "alliance_points",
+                "award_points",
+                "district_cmp",
+                "elim_points",
+                "event_key",
+                "qual_points",
+                "total"
+              ],
+              "type": "object",
+              "properties": {
+                "district_cmp": {
+                  "type": "boolean",
+                  "description": "`true` if this event is a District Championship event."
+                },
+                "total": {
+                  "type": "integer",
+                  "description": "Total points awarded at this event."
+                },
+                "alliance_points": {
+                  "type": "integer",
+                  "description": "Points awarded for alliance selection."
+                },
+                "elim_points": {
+                  "type": "integer",
+                  "description": "Points awarded for elimination match performance."
+                },
+                "award_points": {
+                  "type": "integer",
+                  "description": "Points awarded for event awards."
+                },
+                "event_key": {
+                  "type": "string",
+                  "description": "TBA Event key for this event."
+                },
+                "qual_points": {
+                  "type": "integer",
+                  "description": "Points awarded for qualification match performance."
+                }
+              }
+            }
+          }
+        },
+        "description": "Rank of a team in a district."
+      },
+      "WLT_Record": {
+        "required": [
+          "losses",
+          "ties",
+          "wins"
+        ],
+        "type": "object",
+        "properties": {
+          "losses": {
+            "type": "integer",
+            "description": "Number of losses."
+          },
+          "wins": {
+            "type": "integer",
+            "description": "Number of wins."
+          },
+          "ties": {
+            "type": "integer",
+            "description": "Number of ties."
+          }
+        },
+        "description": "A Win-Loss-Tie record for a team, or an alliance."
+      },
+      "Webcast": {
+        "required": [
+          "channel",
+          "type"
+        ],
+        "type": "object",
+        "properties": {
+          "type": {
+            "type": "string",
+            "description": "Type of webcast, typically descriptive of the streaming provider.",
+            "enum": [
+              "youtube",
+              "twitch",
+              "ustream",
+              "iframe",
+              "html5",
+              "rtmp",
+              "livestream",
+              "direct_link",
+              "mms",
+              "justin",
+              "stemtv",
+              "dacast"
+            ]
+          },
+          "channel": {
+            "type": "string",
+            "description": "Type specific channel information. May be the YouTube stream, or Twitch channel name. In the case of iframe types, contains HTML to embed the stream in an HTML iframe."
+          },
+          "date": {
+            "type": "string",
+            "description": "The date for the webcast in `yyyy-mm-dd` format. May be null."
+          },
+          "file": {
+            "type": "string",
+            "description": "File identification as may be required for some types. May be null."
+          }
+        }
+      }
+    },
+    "responses": {
+      "Unauthorized": {
+        "$ref": "#/components/responses/Unauthorized"
+
+      },
+      "NotModified": {
+        "description": "Not Modified - Use Local Cached Value"
+      }
+    },
+    "parameters": {
+      "year": {
+        "name": "year",
+        "in": "path",
+        "description": "Competition Year (or Season). Must be 4 digits.",
+        "required": true,
+        "schema": {
+          "type": "integer"
+        }
+      },
+      "media_tag": {
+        "name": "media_tag",
+        "in": "path",
+        "description": "Media Tag which describes the Media.",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      },
+      "If-Modified-Since": {
+        "name": "If-Modified-Since",
+        "in": "header",
+        "description": "Value of the `Last-Modified` header in the most recently cached response by the client.",
+        "schema": {
+          "type": "string"
+        }
+      },
+      "page_num": {
+        "name": "page_num",
+        "in": "path",
+        "description": "Page number of results to return, zero-indexed",
+        "required": true,
+        "schema": {
+          "type": "integer"
+        }
+      },
+      "match_key": {
+        "name": "match_key",
+        "in": "path",
+        "description": "TBA Match Key, eg `2016nytr_qm1`",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      },
+      "district_key": {
+        "name": "district_key",
+        "in": "path",
+        "description": "TBA District Key, eg `2016fim`",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      },
+      "team_key": {
+        "name": "team_key",
+        "in": "path",
+        "description": "TBA Team Key, eg `frc254`",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      },
+      "event_key": {
+        "name": "event_key",
+        "in": "path",
+        "description": "TBA Event Key, eg `2016nytr`",
+        "required": true,
+        "schema": {
+          "type": "string"
+        }
+      }
+    },
+    "securitySchemes": {
+      "apiKey": {
+        "type": "apiKey",
+        "description": "Your TBA v3 API Key can be obtained from your [Account Page](/account) on the TBA website.",
+        "name": "X-TBA-Auth-Key",
+        "in": "header"
+      }
+    }
+  }
+}
diff --git a/_testdata/negative/cyclic_parameter.json b/_testdata/negative/cyclic_parameter.json
new file mode 100644
index 00000000..06ce5005
--- /dev/null
+++ b/_testdata/negative/cyclic_parameter.json
@@ -0,0 +1,73 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "title",
+    "version": "v0.1.0"
+  },
+  "paths": {
+    "/healthz": {
+      "get": {
+        "operationId": "probeLiveness",
+        "description": "Liveness probe for kubernetes",
+        "parameters": [
+          {
+            "$ref": "#/components/parameters/Parameter"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "User info",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "default": {
+            "$ref": "#/components/responses/Error"
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "Error": {
+        "description": "Represents error object",
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "message": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "code",
+          "message"
+        ]
+      }
+    },
+    "parameters": {
+      "Parameter": {
+        "$ref": "#/components/parameters/Parameter"
+      }
+    },
+    "responses": {
+      "Error": {
+        "description": "General Error",
+        "content": {
+          "application/json": {
+            "schema": {
+              "$ref": "#/components/schemas/Error"
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/_testdata/negative/cyclic_request.json b/_testdata/negative/cyclic_request.json
new file mode 100644
index 00000000..fa2b482f
--- /dev/null
+++ b/_testdata/negative/cyclic_request.json
@@ -0,0 +1,71 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "title",
+    "version": "v0.1.0"
+  },
+  "paths": {
+    "/healthz": {
+      "get": {
+        "operationId": "probeLiveness",
+        "description": "Liveness probe for kubernetes",
+        "requestBody": {
+          "$ref": "#/components/requestBodies/Request"
+        },
+        "responses": {
+          "200": {
+            "description": "User info",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "default": {
+            "$ref": "#/components/responses/Error"
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "Error": {
+        "description": "Represents error object",
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "message": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "code",
+          "message"
+        ]
+      }
+    },
+    "requestBodies": {
+      "Request": {
+        "$ref": "#/components/requestBodies/Request"
+      }
+    },
+    "responses": {
+      "Error": {
+        "description": "General Error",
+        "content": {
+          "application/json": {
+            "schema": {
+              "$ref": "#/components/schemas/Error"
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/_testdata/negative/cyclic_response.json b/_testdata/negative/cyclic_response.json
new file mode 100644
index 00000000..38ebb57d
--- /dev/null
+++ b/_testdata/negative/cyclic_response.json
@@ -0,0 +1,56 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "title",
+    "version": "v0.1.0"
+  },
+  "paths": {
+    "/healthz": {
+      "get": {
+        "operationId": "probeLiveness",
+        "description": "Liveness probe for kubernetes",
+        "responses": {
+          "200": {
+            "description": "User info",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "string"
+                }
+              }
+            }
+          },
+          "default": {
+            "$ref": "#/components/responses/Error"
+          }
+        }
+      }
+    }
+  },
+  "components": {
+    "schemas": {
+      "Error": {
+        "description": "Represents error object",
+        "type": "object",
+        "properties": {
+          "code": {
+            "type": "integer",
+            "format": "int64"
+          },
+          "message": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "code",
+          "message"
+        ]
+      }
+    },
+    "responses": {
+      "Error": {
+        "$ref": "#/components/responses/Error"
+      }
+    }
+  }
+}