{
  "openapi": "3.1.0",
  "info": {
    "title": "Citadel game data API",
    "version": "1.0.0",
    "summary": "Public, versioned game data and ship-fit tools for the live build of Citadel.",
    "description": "Game data and fit tools for [Citadel](https://thecitadel.com), always from the live build. The fit tools run the game's own code, so they apply the same rules the game does.\n\n### Rules\n\n- Send a `User-Agent` with your app's name and a way to reach you. Requests with none, or a generic one such as curl or python-requests, still work, but the response carries a `Warning` header.\n- Each client can make 60 requests in a burst, and the allowance refills at 10 a second. Art and `sde.zip` have allowances of their own. Past the limit you get a 429 with `Retry-After`.\n- Send the last response's ETag in `If-None-Match` and you get a 304 until the data changes. `X-Citadel-Build` (or `/v1/status`) tells you when the build changes. If you want everything, download `/v1/sde.zip` once instead of crawling every route.\n\n### Conventions\n\n- An id is the game's asset GUID as a decimal string, and it doesn't change between builds. Boss NPCs that are elite archetypes have ids like `boss:JUGGERNAUT`.\n- Fixed-point values are raw decimal strings: divide by 65536.\n- Enum values are the game's own names. New content brings new values, so don't treat any enum as complete.\n- Errors look like `{ \"error\": { \"code\", \"message\" } }` and use status 400, 404, 405, 413, 415, 429, 500 or 503.\n- Every response carries `X-Citadel-Build`, `Access-Control-Allow-Origin: *` and an `ETag`.\n\n### Stability\n\nNew routes and fields can appear at any time, without notice, so ignore fields you don't recognise. Removing or renaming a field, or changing what it means or its type, only happens in `/v2`. When `/v2` ships, `/v1` keeps running for at least 90 days and its responses carry a `Deprecation` header. Game data isn't part of that promise: items come and go with builds.\n\nThe data and art belong to the game; see the [terms](/docs/TERMS.md).",
    "termsOfService": "https://api.thecitadel.com/docs/TERMS.md"
  },
  "servers": [
    {
      "url": "https://api.thecitadel.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Status",
      "description": "Which build is live."
    },
    {
      "name": "Static data",
      "description": "The live build's content, as full lists or one record at a time."
    },
    {
      "name": "Art",
      "description": "Icons as WebP."
    },
    {
      "name": "Bulk",
      "description": "All the data in one download, and this OpenAPI document."
    },
    {
      "name": "Tools",
      "description": "Check a fit, convert it to and from the in-game fit string, or read an item's tooltip rows."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Data",
      "tags": [
        "Status",
        "Static data",
        "Art",
        "Bulk"
      ]
    },
    {
      "name": "Tools",
      "tags": [
        "Tools"
      ]
    }
  ],
  "paths": {
    "/v1/status": {
      "get": {
        "operationId": "getStatus",
        "tags": [
          "Status"
        ],
        "summary": "The live build",
        "description": "When a new build goes live, `build` changes, so poll this to find out. Every other response carries the build in the `X-Citadel-Build` header.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getStatusHead",
        "tags": [
          "Status"
        ],
        "summary": "The live build (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Status"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/items": {
      "get": {
        "operationId": "listItems",
        "tags": [
          "Static data"
        ],
        "summary": "Fittable modules and conduits",
        "description": "Every module and conduit players can get in the live build.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listItemsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Fittable modules and conduits (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ItemList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/items/{id}": {
      "get": {
        "operationId": "getItem",
        "tags": [
          "Static data"
        ],
        "summary": "One item",
        "parameters": [
          {
            "$ref": "#/components/parameters/ItemId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getItemHead",
        "tags": [
          "Static data"
        ],
        "summary": "One item (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ItemId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Item"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/hulls": {
      "get": {
        "operationId": "listHulls",
        "tags": [
          "Static data"
        ],
        "summary": "Hulls",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HullList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listHullsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Hulls (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HullList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/hulls/{id}": {
      "get": {
        "operationId": "getHull",
        "tags": [
          "Static data"
        ],
        "summary": "One hull",
        "parameters": [
          {
            "$ref": "#/components/parameters/HullId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hull"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getHullHead",
        "tags": [
          "Static data"
        ],
        "summary": "One hull (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/HullId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hull"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/ciphers": {
      "get": {
        "operationId": "listCiphers",
        "tags": [
          "Static data"
        ],
        "summary": "Ciphers",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CipherList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listCiphersHead",
        "tags": [
          "Static data"
        ],
        "summary": "Ciphers (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CipherList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/artifacts": {
      "get": {
        "operationId": "listArtifacts",
        "tags": [
          "Static data"
        ],
        "summary": "Artifacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtifactList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listArtifactsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Artifacts (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArtifactList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/regalia-sets": {
      "get": {
        "operationId": "listRegaliaSets",
        "tags": [
          "Static data"
        ],
        "summary": "Regalia sets",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegaliaSetList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listRegaliaSetsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Regalia sets (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegaliaSetList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/regalia": {
      "get": {
        "operationId": "listRegalia",
        "tags": [
          "Static data"
        ],
        "summary": "Regalia pieces",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegaliaList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listRegaliaHead",
        "tags": [
          "Static data"
        ],
        "summary": "Regalia pieces (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegaliaList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/heretical-specials": {
      "get": {
        "operationId": "listHereticalSpecials",
        "tags": [
          "Static data"
        ],
        "summary": "Heretical specials",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HereticalSpecialList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listHereticalSpecialsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Heretical specials (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HereticalSpecialList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/harmonic-sets": {
      "get": {
        "operationId": "listHarmonicSets",
        "tags": [
          "Static data"
        ],
        "summary": "Harmonic sets",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HarmonicSetList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listHarmonicSetsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Harmonic sets (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HarmonicSetList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/modifier-pools": {
      "get": {
        "operationId": "listModifierPools",
        "tags": [
          "Static data"
        ],
        "summary": "Modifier pools per module type",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModifierPoolList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listModifierPoolsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Modifier pools per module type (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModifierPoolList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/qualities": {
      "get": {
        "operationId": "listQualities",
        "tags": [
          "Static data"
        ],
        "summary": "Quality rating multipliers",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QualityList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listQualitiesHead",
        "tags": [
          "Static data"
        ],
        "summary": "Quality rating multipliers (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QualityList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/placement-rules": {
      "get": {
        "operationId": "listPlacementRules",
        "tags": [
          "Static data"
        ],
        "summary": "Where each slot type may sit on a fitting grid",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlacementRuleList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listPlacementRulesHead",
        "tags": [
          "Static data"
        ],
        "summary": "Where each slot type may sit on a fitting grid (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlacementRuleList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/affinity": {
      "get": {
        "operationId": "getAffinity",
        "tags": [
          "Static data"
        ],
        "summary": "The affinity tree",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffinityResponse"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getAffinityHead",
        "tags": [
          "Static data"
        ],
        "summary": "The affinity tree (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AffinityResponse"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/npcs": {
      "get": {
        "operationId": "listNpcs",
        "tags": [
          "Static data"
        ],
        "summary": "NPC ships, bosses and their weapons",
        "description": "The NPC ships, bosses and weapons players run into. This is the only list that includes things players can't obtain. A boss with no prototype of its own has the id `boss:<archetypeId>`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NpcList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listNpcsHead",
        "tags": [
          "Static data"
        ],
        "summary": "NPC ships, bosses and their weapons (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NpcList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "operationId": "listStats",
        "tags": [
          "Static data"
        ],
        "summary": "Every stat type",
        "description": "Each stat type with the game's label for it and the rules the game uses to display its values.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "listStatsHead",
        "tags": [
          "Static data"
        ],
        "summary": "Every stat type (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatList"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/art/{file}": {
      "get": {
        "operationId": "getArt",
        "tags": [
          "Art"
        ],
        "summary": "A WebP image",
        "description": "Art for items, hulls, ciphers, artifacts and NPCs. Take file names from the `art` object on each record. A file name is a hash of the image, so the file behind it never changes and you can cache it for a year. Art has its own, larger rate limit: 600 requests, refilling at 100 a second.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArtFile"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "The WebP image.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "description": "`public, max-age=31536000, immutable`, because the file name contains a hash of the image.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getArtHead",
        "tags": [
          "Art"
        ],
        "summary": "A WebP image (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ArtFile"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "description": "`public, max-age=31536000, immutable`, because the file name contains a hash of the image.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/sde.zip": {
      "get": {
        "operationId": "getSde",
        "tags": [
          "Bulk"
        ],
        "summary": "Every static resource and the art in one zip",
        "description": "Built once when the API starts. It holds one JSON file per static route (`status.json`, `items.json`, `hulls.json`, `ciphers.json`, `artifacts.json`, `regalia-sets.json`, `affinity.json`, `npcs.json`, `stats.json`, `regalia.json`, `heretical-specials.json`, `harmonic-sets.json`, `modifier-pools.json`, `qualities.json`, `placement-rules.json`), the art under `art/` with the art manifest, and `manifest.json`, which names the build and gives a SHA-256 for every other file. Each JSON file is byte for byte what its route serves. The zip is built deterministically, so its ETag changes only when the data does. It has its own rate limit: 5 downloads, then one more every 6 seconds.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getSdeHead",
        "tags": [
          "Bulk"
        ],
        "summary": "Every static resource and the art in one zip (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/openapi.json": {
      "get": {
        "operationId": "getOpenApi",
        "tags": [
          "Bulk"
        ],
        "summary": "This OpenAPI document",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "An OpenAPI 3.1 document."
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      },
      "head": {
        "operationId": "getOpenApiHead",
        "tags": [
          "Bulk"
        ],
        "summary": "This OpenAPI document (headers only)",
        "description": "Same status and headers as GET, with no body.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              },
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "An OpenAPI 3.1 document."
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/fits/evaluate": {
      "post": {
        "operationId": "evaluateFit",
        "tags": [
          "Tools"
        ],
        "summary": "Evaluate a fit",
        "description": "Runs the game's own simulation on the fit and returns its issues, conduit links, regalia groups, stat lines, hull spec sections and rating. Bodies can be up to 256 KB, and a request whose body fails validation still counts against the rate limit. The fit may use any item the build defines, so a pasted fit always loads; anything illegal about it shows up in `issues`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FitBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Evaluation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/fits/import": {
      "post": {
        "operationId": "importFit",
        "tags": [
          "Tools"
        ],
        "summary": "Convert a fit string to a fit",
        "description": "Decodes the game's shareable fit string into a fit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FitStringBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FitBody"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/fits/export": {
      "post": {
        "operationId": "exportFit",
        "tags": [
          "Tools"
        ],
        "summary": "Convert a fit to a fit string",
        "description": "Encodes a fit as the game's shareable fit string.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FitBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FitStringBody"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    },
    "/v1/items/facts": {
      "post": {
        "operationId": "itemFacts",
        "tags": [
          "Tools"
        ],
        "summary": "Tooltip rows for a rolled item",
        "description": "The rows the game's item tooltip shows for this roll.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ItemBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "headers": {
              "X-Citadel-Build": {
                "$ref": "#/components/headers/Build"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/CORS"
              },
              "Warning": {
                "$ref": "#/components/headers/Warning"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FactsBody"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/Internal"
          },
          "503": {
            "$ref": "#/components/responses/Starting"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorEnvelope": {
        "type": "object",
        "description": "Every error response has this body, with the matching HTTP status.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "A fixed code for the kind of error, such as `not_found`.",
                "enum": [
                  "bad_request",
                  "not_found",
                  "too_large",
                  "rate_limited",
                  "starting",
                  "internal"
                ]
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in English."
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ArtKeys": {
        "type": "object",
        "description": "Art for one record. Tier variants appear only where the game has separate art for a tier. They're named after the game's rarities, which is why they're capitalised and the other fields aren't.",
        "properties": {
          "base": {
            "type": "string",
            "description": "API-relative URL of the 128px WebP. For the 256px version, put `@2x` before `.webp`.",
            "pattern": "^/v1/art/[a-z0-9.@_-]+\\.webp$"
          },
          "Augmented": {
            "type": "string",
            "description": "Art for the Augmented tier.",
            "pattern": "^/v1/art/"
          },
          "Prototype": {
            "type": "string",
            "description": "Art for the Prototype tier.",
            "pattern": "^/v1/art/"
          },
          "Artifact": {
            "type": "string",
            "description": "Art for an artifact of the item.",
            "pattern": "^/v1/art/"
          },
          "Heretical": {
            "type": "string",
            "description": "Art for the Heretical tier.",
            "pattern": "^/v1/art/"
          }
        },
        "required": [
          "base"
        ]
      },
      "FactRow": {
        "type": "object",
        "description": "One row of an item tooltip, in the game's own wording. `label` and `value` are upper case, as in the game.",
        "properties": {
          "label": {
            "type": "string"
          },
          "value": {
            "type": [
              "string",
              "null"
            ]
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "tone": {
            "type": "string",
            "description": "How the game colours the row.",
            "enum": [
              "Neutral",
              "Positive",
              "Negative"
            ]
          },
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "The game's `TooltipStatId` for the stat on this row, such as `CycleDuration` for a turret's FIRE RATE, `TurretReloadRateIdle` for IDLE RECHARGE and `TurretMagazineSize` for MAGAZINE SIZE. Use it to find a row without matching on its label. Null when the game gives the row no id."
          },
          "number": {
            "type": [
              "number",
              "null"
            ],
            "description": "The unrounded number behind `value`, in `unit`: where the tooltip reads 2.9 s, this can be 2.94. It already includes the game's distance scaling and its metre-to-kilometre step, and a multiplier modifier line gives it as a percent. Null when the value is a word. A number that comes from a fixed-point game value is exact to 1/65536."
          }
        },
        "required": [
          "label",
          "value",
          "unit",
          "tone",
          "id",
          "number"
        ]
      },
      "Cell": {
        "type": "object",
        "properties": {
          "row": {
            "type": "integer"
          },
          "col": {
            "type": "integer"
          }
        },
        "required": [
          "row",
          "col"
        ]
      },
      "Shape": {
        "type": "object",
        "description": "The item's footprint at rotation 0, on the 5x5 shape grid that ports are anchored to. An item placed at (row, col) covers grid cell (row + cell.row - originRow, col + cell.col - originCol).",
        "properties": {
          "originRow": {
            "type": "integer"
          },
          "originCol": {
            "type": "integer"
          },
          "cells": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Cell"
            }
          }
        },
        "required": [
          "originRow",
          "originCol",
          "cells"
        ]
      },
      "PortCandidate": {
        "type": "object",
        "properties": {
          "row": {
            "type": "integer"
          },
          "col": {
            "type": "integer"
          },
          "direction": {
            "type": "string",
            "description": "Up, Down, Left or Right."
          }
        },
        "required": [
          "row",
          "col",
          "direction"
        ]
      },
      "PortRules": {
        "type": "object",
        "description": "An item has at most `maxPorts` ports. Each is one of `candidates`, and no two are the same. Only modules have ports.",
        "properties": {
          "maxPorts": {
            "type": "integer"
          },
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortCandidate"
            }
          }
        },
        "required": [
          "maxPorts",
          "candidates"
        ]
      },
      "Tier": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "integer"
          },
          "min": {
            "type": "string",
            "description": "The lowest value a roll can have, inclusive, as raw fixed point.",
            "pattern": "^-?[0-9]+$"
          },
          "max": {
            "type": "string",
            "description": "The highest value a roll can have, inclusive, as raw fixed point.",
            "pattern": "^-?[0-9]+$"
          },
          "allowed": {
            "type": "boolean"
          }
        },
        "required": [
          "tier",
          "min",
          "max",
          "allowed"
        ]
      },
      "PoolEntry": {
        "type": "object",
        "description": "A modifier line an item can roll.",
        "properties": {
          "stat": {
            "type": "string",
            "description": "A stat id from /v1/stats."
          },
          "operation": {
            "type": "string",
            "description": "Add or Multiply."
          },
          "pool": {
            "type": "string",
            "description": "A module type name, or Role:<ShipRole> for a hull's role pool."
          },
          "group": {
            "type": "integer",
            "description": "Entries in one pool that share a nonzero group exclude each other: an item rolls at most one of them."
          },
          "augmentedOnly": {
            "type": "boolean",
            "description": "Drops only on Augmented items, and stays on an item that becomes Prototype."
          },
          "onlyOnModule": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$",
            "description": "When set, the line rolls only on the item with this id."
          },
          "tiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tier"
            }
          }
        },
        "required": [
          "stat",
          "operation",
          "pool",
          "group",
          "augmentedOnly",
          "onlyOnModule",
          "tiers"
        ]
      },
      "ModifierSlots": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PoolEntry"
            }
          },
          "suffix": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PoolEntry"
            }
          }
        },
        "required": [
          "prefix",
          "suffix"
        ]
      },
      "ModifierCount": {
        "type": "object",
        "properties": {
          "rarity": {
            "type": "string"
          },
          "min": {
            "type": "integer"
          },
          "max": {
            "type": "integer"
          }
        },
        "required": [
          "rarity",
          "min",
          "max"
        ]
      },
      "AuthoredRoll": {
        "type": "object",
        "description": "A roll the game's config allows outright: an item with this quality and rarity and no modifiers, ports or references is legal, and its rating is `pointRating`.",
        "properties": {
          "source": {
            "type": "string"
          },
          "quality": {
            "type": "string"
          },
          "rarity": {
            "type": "string"
          },
          "isIdentified": {
            "type": "boolean"
          },
          "pointRating": {
            "type": "integer"
          }
        },
        "required": [
          "source",
          "quality",
          "rarity",
          "isIdentified",
          "pointRating"
        ]
      },
      "ItemRating": {
        "type": "object",
        "description": "How the game computes an item's stored rating: floor((base + contribution) x quality multiplier), plus the `pointRating` of each slotted cipher and of a harmonic set. The multiplier is 1 unless `scalesWithQuality` is set.",
        "properties": {
          "base": {
            "type": "integer"
          },
          "scalesWithQuality": {
            "type": "boolean"
          },
          "tierShares": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "regaliaShare": {
            "type": "integer"
          },
          "hereticalShare": {
            "type": "integer"
          },
          "ascendedHereticalShare": {
            "type": "integer"
          }
        },
        "required": [
          "base",
          "scalesWithQuality",
          "tierShares",
          "regaliaShare",
          "hereticalShare",
          "ascendedHereticalShare"
        ]
      },
      "Roll": {
        "type": "object",
        "description": "Everything an item can roll. References are ids from the other routes.",
        "properties": {
          "qualities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Qualities the item can have, as names."
          },
          "rarities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "modifierCounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModifierCount"
            },
            "description": "How many modifiers each modifier-bearing rarity holds."
          },
          "modifierPool": {
            "$ref": "#/components/schemas/ModifierSlots"
          },
          "typeOverrides": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Module types a THOTH adapter can give the item."
          },
          "artifacts": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            },
            "description": "Ids from /v1/artifacts."
          },
          "regalia": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            },
            "description": "Ids from /v1/regalia."
          },
          "hereticals": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            },
            "description": "Ids from /v1/heretical-specials."
          },
          "harmonicSets": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            },
            "description": "Ids from /v1/harmonic-sets."
          },
          "rating": {
            "$ref": "#/components/schemas/ItemRating"
          },
          "authored": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuthoredRoll"
            }
          }
        },
        "required": [
          "qualities",
          "rarities",
          "modifierCounts",
          "modifierPool",
          "typeOverrides",
          "artifacts",
          "regalia",
          "hereticals",
          "harmonicSets",
          "rating",
          "authored"
        ]
      },
      "Item": {
        "type": "object",
        "description": "A fittable module or conduit players can obtain.",
        "properties": {
          "def": {
            "type": "string",
            "description": "The item's id.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "The item's description from the game, or null."
          },
          "facts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FactRow"
            },
            "description": "Tooltip rows for the item's plainest roll. Each row carries the exact `number` behind its text and the game's `id` for its stat, so a turret's FIRE RATE (`CycleDuration`, seconds between shots), IDLE RECHARGE (`TurretReloadRateIdle`) and MAGAZINE SIZE (`TurretMagazineSize`) each come as a separate row."
          },
          "category": {
            "type": "string",
            "description": "Module or Conduit."
          },
          "slotType": {
            "type": "string"
          },
          "slotSize": {
            "type": "string"
          },
          "moduleType": {
            "type": "string"
          },
          "targeting": {
            "type": "string",
            "description": "The module's `ModuleTargetingPolicy`: `CasterAnchored` (own ship), `SelectedEnemy`, `SelectedSquadAlly` (a squadmate), `WorldAim` or `EnemyAreaAroundCaster`."
          },
          "ability": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ability"
              },
              {
                "type": "null"
              }
            ],
            "description": "The battery ability this module gives its battery, as a turret does, or null."
          },
          "payloads": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "shape": {
            "$ref": "#/components/schemas/Shape"
          },
          "portRules": {
            "$ref": "#/components/schemas/PortRules"
          },
          "roll": {
            "$ref": "#/components/schemas/Roll"
          },
          "art": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArtKeys"
              },
              {
                "type": "null"
              }
            ]
          },
          "autoActivateOnOverheat": {
            "type": "boolean",
            "description": "The game's `isAutoActivateOnOverheat`. When true, the module switches itself on when its ship enters the Unstable heat zone."
          }
        },
        "required": [
          "def",
          "name",
          "description",
          "facts",
          "category",
          "slotType",
          "slotSize",
          "moduleType",
          "payloads",
          "shape",
          "portRules",
          "roll",
          "art",
          "targeting",
          "ability",
          "autoActivateOnOverheat"
        ]
      },
      "Hull": {
        "type": "object",
        "description": "A hull players can obtain.",
        "properties": {
          "def": {
            "type": "string",
            "description": "The hull's id.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "shipClass": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "description": "The ship role the hull unlocks, or None."
          },
          "rows": {
            "type": "integer"
          },
          "cols": {
            "type": "integer"
          },
          "slots": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A slot type name."
            },
            "description": "The fitting grid in row-major order, with rows x cols entries."
          },
          "baseCargoCapacity": {
            "type": "integer",
            "description": "The hull's cargo slots before bonuses from fitted modules (`ShipStats.baseCargoCapacity`). 0 means the game's maximum cargo size."
          },
          "safetyHoldSlots": {
            "type": "integer",
            "description": "How many safety cargo cells the hull has: cargo cells whose items survive ship loss (`ShipFitting.safetyCargoSlotCount`). `/v1/fits/evaluate` reports the same value as `safety-hold-slots`."
          },
          "roll": {
            "$ref": "#/components/schemas/Roll"
          },
          "art": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArtKeys"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "def",
          "name",
          "shipClass",
          "role",
          "rows",
          "cols",
          "slots",
          "roll",
          "art",
          "baseCargoCapacity",
          "safetyHoldSlots"
        ]
      },
      "Cipher": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "stat": {
            "type": "string"
          },
          "operation": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          },
          "pointRating": {
            "type": "integer"
          },
          "art": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArtKeys"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "def",
          "name",
          "stat",
          "operation",
          "value",
          "pointRating",
          "art"
        ]
      },
      "TemplateLine": {
        "type": "object",
        "properties": {
          "stat": {
            "type": "string"
          },
          "operation": {
            "type": "string"
          },
          "tier": {
            "type": "integer"
          },
          "min": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          },
          "max": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          },
          "scope": {
            "type": "string",
            "enum": [
              "Local",
              "ShipWide"
            ],
            "description": "`Local` when a line of this stat affects only the item's own module, `ShipWide` when it affects the whole ship. The game decides this with `StatEffectModuleSystem.IsLocalToModule` on the base module: a turret's, launcher's or minelayer's own weapon stats are local, and so is `PortCount`."
          },
          "row": {
            "$ref": "#/components/schemas/FactRow",
            "description": "The range as the tooltip shows a rolled line's bounds (`ItemModifierText.RollRange`). `value` holds the range, such as `8-14`, or `-5 to +5` when it crosses zero, and `unit` is `%` for a multiplier or resistance. When the range sits on one side of zero, the sign is on `minRow` and `maxRow`."
          },
          "minRow": {
            "$ref": "#/components/schemas/FactRow",
            "description": "The lower bound (`min`) as the tooltip shows a line with that value, such as `+8%`."
          },
          "maxRow": {
            "$ref": "#/components/schemas/FactRow",
            "description": "The upper bound (`max`) as the tooltip shows a line with that value."
          }
        },
        "required": [
          "stat",
          "operation",
          "tier",
          "min",
          "max",
          "scope",
          "row",
          "minRow",
          "maxRow"
        ]
      },
      "ScaledStatRange": {
        "type": "object",
        "properties": {
          "rule": {
            "type": "string"
          },
          "min": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          },
          "max": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          }
        },
        "required": [
          "rule",
          "min",
          "max"
        ]
      },
      "Artifact": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "item": {
            "type": "string",
            "description": "The base item the artifact is a version of.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateLine"
            },
            "description": "The artifact's lines, in order."
          },
          "scaledStat": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScaledStatRange"
              },
              {
                "type": "null"
              }
            ]
          },
          "pointRating": {
            "type": "integer"
          },
          "patinaMax": {
            "type": "integer"
          },
          "targeting": {
            "type": "string",
            "description": "The `ModuleTargetingPolicy` of the artifact's base module, which the artifact is cast as."
          },
          "ability": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Ability"
              },
              {
                "type": "null"
              }
            ],
            "description": "The artifact's own battery ability, which takes over its battery. Null when the artifact keeps its base module's ability."
          },
          "art": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArtKeys"
              },
              {
                "type": "null"
              }
            ],
            "description": "Only artifacts with an icon of their own have art. The rest use their base item's."
          }
        },
        "required": [
          "def",
          "name",
          "item",
          "modifiers",
          "scaledStat",
          "pointRating",
          "patinaMax",
          "art",
          "targeting",
          "ability"
        ]
      },
      "Regalia": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "item": {
            "type": "string",
            "description": "The base item.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "set": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$",
            "description": "The regalia set it belongs to."
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateLine"
            }
          },
          "scaledStat": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ScaledStatRange"
              },
              {
                "type": "null"
              }
            ]
          },
          "linkedBonuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SetBonus"
            },
            "description": "What this piece itself grants once 2, 3 or 4 pieces of its set are linked (the game's `partialSetBonuses`)."
          }
        },
        "required": [
          "def",
          "name",
          "item",
          "set",
          "modifiers",
          "scaledStat",
          "linkedBonuses"
        ]
      },
      "RegaliaSet": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "pieces": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A regalia id.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            }
          },
          "bonuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SetBonus"
            },
            "description": "The set's bonuses by number of linked pieces, as a set-bonus table shows them (the game's `bonus2Piece`, `bonus3Piece` and `bonus4Piece`)."
          }
        },
        "required": [
          "def",
          "name",
          "pieces",
          "bonuses"
        ]
      },
      "HereticalSpecial": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "heresy": {
            "type": "string"
          },
          "ascended": {
            "type": "boolean"
          },
          "moduleTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "def",
          "name",
          "heresy",
          "ascended",
          "moduleTypes"
        ]
      },
      "HarmonicSet": {
        "type": "object",
        "description": "A Normal module whose ports hold exactly these ciphers, in any order, takes the set's cipher key.",
        "properties": {
          "def": {
            "type": "string",
            "description": "An asset GUID as a decimal string: a signed 64-bit integer with no plus sign or leading zeros.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "moduleTypes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "ciphers": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "A cipher id.",
              "pattern": "^(0|-?[1-9][0-9]*)$"
            }
          },
          "pointRating": {
            "type": "integer"
          }
        },
        "required": [
          "def",
          "name",
          "description",
          "moduleTypes",
          "ciphers",
          "pointRating"
        ]
      },
      "ModifierPool": {
        "type": "object",
        "properties": {
          "moduleType": {
            "type": "string"
          },
          "modifiers": {
            "$ref": "#/components/schemas/ModifierSlots"
          }
        },
        "required": [
          "moduleType",
          "modifiers"
        ]
      },
      "Quality": {
        "type": "object",
        "properties": {
          "quality": {
            "type": "string"
          },
          "multiplier": {
            "type": "string",
            "description": "The rating multiplier, raw fixed point.",
            "pattern": "^-?[0-9]+$"
          }
        },
        "required": [
          "quality",
          "multiplier"
        ]
      },
      "PlacementRule": {
        "type": "object",
        "description": "Where an item of `slotType` may sit. Every cell it covers must be one of `covers`, and when `hardpoint` is set, at least one of those cells must be of that type.",
        "properties": {
          "slotType": {
            "type": "string"
          },
          "covers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hardpoint": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "slotType",
          "covers",
          "hardpoint"
        ]
      },
      "AffinityChoice": {
        "type": "object",
        "properties": {
          "option": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "option",
          "name",
          "description"
        ]
      },
      "AffinityTier": {
        "type": "object",
        "properties": {
          "tier": {
            "type": "integer"
          },
          "requiredPoints": {
            "type": "integer"
          },
          "choices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffinityChoice"
            }
          }
        },
        "required": [
          "tier",
          "requiredPoints",
          "choices"
        ]
      },
      "AffinityBonus": {
        "type": "object",
        "properties": {
          "option": {
            "type": "integer"
          },
          "stat": {
            "type": "string"
          },
          "operation": {
            "type": "string"
          },
          "valuePerPoint": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "invertDisplaySign": {
            "type": "boolean"
          }
        },
        "required": [
          "option",
          "stat",
          "operation",
          "valuePerPoint",
          "name",
          "description",
          "invertDisplaySign"
        ]
      },
      "AffinityType": {
        "type": "object",
        "properties": {
          "moduleType": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "optionName": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "bonuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffinityBonus"
            }
          },
          "thresholds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffinityTier"
            }
          }
        },
        "required": [
          "moduleType",
          "name",
          "optionName",
          "description",
          "bonuses",
          "thresholds"
        ]
      },
      "Affinity": {
        "type": "object",
        "description": "The affinity tree.",
        "properties": {
          "maxLevel": {
            "type": "integer"
          },
          "maxPointsPerCategory": {
            "type": "integer"
          },
          "maxPointsPerBonus": {
            "type": "integer"
          },
          "levelXp": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "`levelXp[level - 1]` is the XP a level needs."
          },
          "ratingByPoints": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Rating added by the total points spent."
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AffinityType"
            }
          }
        },
        "required": [
          "maxLevel",
          "maxPointsPerCategory",
          "maxPointsPerBonus",
          "levelXp",
          "ratingByPoints",
          "types"
        ]
      },
      "Npc": {
        "type": "object",
        "description": "An NPC ship, boss or NPC-only weapon that players run into. v1 doesn't include their stats or behaviour.",
        "properties": {
          "id": {
            "type": "string",
            "description": "A GUID as a decimal string, or `boss:<archetypeId>` for a boss that is an elite archetype with no prototype of its own. NPC weapons have item GUIDs, but `/v1/items/{id}` doesn't serve them because players can't obtain those weapons.",
            "pattern": "^((0|-?[1-9][0-9]*)|boss:.+)$"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "What it is.",
            "enum": [
              "ship",
              "boss",
              "weapon"
            ]
          },
          "class": {
            "type": [
              "string",
              "null"
            ],
            "description": "The flown ship's class; null on a weapon."
          },
          "role": {
            "type": [
              "string",
              "null"
            ],
            "description": "The flown ship's role; null when it has none."
          },
          "art": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArtKeys"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "kind",
          "class",
          "role",
          "art"
        ]
      },
      "Stat": {
        "type": "object",
        "description": "One stat type. The game has no unit per stat type, so there is no unit field.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The stat type's name, as used in modifiers and stat lines."
          },
          "label": {
            "type": "string",
            "description": "The game's label."
          },
          "lowerIsBetter": {
            "type": "boolean"
          },
          "integer": {
            "type": "boolean",
            "description": "True when the game treats the stat's values as whole numbers."
          },
          "invertedSign": {
            "type": "boolean",
            "description": "True when the game shows a multiplier's sign inverted."
          }
        },
        "required": [
          "id",
          "label",
          "lowerIsBetter",
          "integer",
          "invertedSign"
        ]
      },
      "Counts": {
        "type": "object",
        "properties": {
          "hulls": {
            "type": "integer"
          },
          "items": {
            "type": "integer"
          },
          "ciphers": {
            "type": "integer"
          },
          "artifacts": {
            "type": "integer"
          },
          "regaliaSets": {
            "type": "integer"
          }
        },
        "required": [
          "hulls",
          "items",
          "ciphers",
          "artifacts",
          "regaliaSets"
        ]
      },
      "Status": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the live build."
          },
          "liveSince": {
            "type": "string",
            "description": "When the build was exported, ISO 8601 UTC.",
            "format": "date-time"
          },
          "counts": {
            "$ref": "#/components/schemas/Counts"
          }
        },
        "required": [
          "build",
          "liveSince",
          "counts"
        ]
      },
      "ItemList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Item"
            }
          }
        },
        "required": [
          "build",
          "items"
        ]
      },
      "HullList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "hulls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Hull"
            }
          }
        },
        "required": [
          "build",
          "hulls"
        ]
      },
      "CipherList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "ciphers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Cipher"
            }
          }
        },
        "required": [
          "build",
          "ciphers"
        ]
      },
      "ArtifactList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "artifacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Artifact"
            }
          }
        },
        "required": [
          "build",
          "artifacts"
        ]
      },
      "RegaliaSetList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "regaliaSets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RegaliaSet"
            }
          }
        },
        "required": [
          "build",
          "regaliaSets"
        ]
      },
      "RegaliaList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "regalia": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Regalia"
            }
          }
        },
        "required": [
          "build",
          "regalia"
        ]
      },
      "HereticalSpecialList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "hereticalSpecials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HereticalSpecial"
            }
          }
        },
        "required": [
          "build",
          "hereticalSpecials"
        ]
      },
      "HarmonicSetList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "harmonicSets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HarmonicSet"
            }
          }
        },
        "required": [
          "build",
          "harmonicSets"
        ]
      },
      "ModifierPoolList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "modifierPools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModifierPool"
            }
          }
        },
        "required": [
          "build",
          "modifierPools"
        ]
      },
      "QualityList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "qualities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Quality"
            }
          }
        },
        "required": [
          "build",
          "qualities"
        ]
      },
      "PlacementRuleList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "placementRules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlacementRule"
            }
          }
        },
        "required": [
          "build",
          "placementRules"
        ]
      },
      "NpcList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "npcs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Npc"
            }
          }
        },
        "required": [
          "build",
          "npcs"
        ]
      },
      "StatList": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "stats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Stat"
            }
          }
        },
        "required": [
          "build",
          "stats"
        ]
      },
      "AffinityResponse": {
        "type": "object",
        "properties": {
          "build": {
            "type": "string",
            "description": "The commit SHA of the build."
          },
          "affinity": {
            "$ref": "#/components/schemas/Affinity"
          }
        },
        "required": [
          "build",
          "affinity"
        ]
      },
      "OpenModifier": {
        "type": "object",
        "properties": {
          "stat": {
            "type": "string",
            "description": "A stat id from /v1/stats."
          },
          "operation": {
            "type": "string"
          },
          "tier": {
            "type": "integer"
          },
          "value": {
            "type": "string",
            "description": "The rolled value, raw fixed point.",
            "pattern": "^-?[0-9]+$"
          },
          "slot": {
            "type": "integer"
          },
          "isInverted": {
            "type": "boolean"
          },
          "isFractured": {
            "type": "boolean"
          }
        },
        "required": [
          "stat",
          "operation",
          "tier",
          "value",
          "slot",
          "isInverted",
          "isFractured"
        ]
      },
      "OpenPort": {
        "type": "object",
        "properties": {
          "row": {
            "type": "integer"
          },
          "col": {
            "type": "integer"
          },
          "direction": {
            "type": "string"
          },
          "cipher": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$",
            "description": "The cipher in the port, or null for an empty one."
          }
        },
        "required": [
          "row",
          "col",
          "direction",
          "cipher"
        ]
      },
      "OpenScaledStat": {
        "type": "object",
        "properties": {
          "rule": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "strength": {
            "type": "string",
            "description": "A fixed-point number as a raw decimal string: divide by 65536.",
            "pattern": "^-?[0-9]+$"
          }
        },
        "required": [
          "rule",
          "strength"
        ]
      },
      "OpenRoll": {
        "type": "object",
        "description": "An item's roll. There's no rating field: the API computes the rating itself and ignores one if you send it.",
        "properties": {
          "quality": {
            "type": "string"
          },
          "rarity": {
            "type": "string"
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenModifier"
            }
          },
          "ports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenPort"
            }
          },
          "artifact": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "regalia": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "heretical": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "ascended": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$",
            "description": "The ascended form that an ascended GULLVEIG BRAND gave, alongside the special in `heretical`."
          },
          "moduleTypeOverride": {
            "type": [
              "string",
              "null"
            ]
          },
          "isIdentified": {
            "type": "boolean"
          },
          "isHarmonized": {
            "type": "boolean"
          },
          "isMirrored": {
            "type": "boolean"
          },
          "harmonicSet": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "scaledStat": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/OpenScaledStat"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "quality",
          "rarity",
          "modifiers",
          "ports",
          "artifact",
          "regalia",
          "heretical",
          "ascended",
          "moduleTypeOverride",
          "isIdentified",
          "isHarmonized",
          "isMirrored",
          "harmonicSet",
          "scaledStat"
        ]
      },
      "OpenItem": {
        "type": "object",
        "properties": {
          "def": {
            "type": "string",
            "description": "An item or hull id. Any item the build defines is accepted, obtainable or not.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "roll": {
            "$ref": "#/components/schemas/OpenRoll"
          },
          "patina": {
            "type": "integer"
          }
        },
        "required": [
          "def",
          "roll",
          "patina"
        ]
      },
      "OpenModule": {
        "type": "object",
        "properties": {
          "item": {
            "$ref": "#/components/schemas/OpenItem"
          },
          "row": {
            "type": "integer"
          },
          "col": {
            "type": "integer"
          },
          "rotation": {
            "type": "integer",
            "description": "Quarter turns, 0 to 3."
          }
        },
        "required": [
          "item",
          "row",
          "col",
          "rotation"
        ]
      },
      "OpenProgression": {
        "type": "object",
        "properties": {
          "affinityType": {
            "type": "string"
          },
          "affinityXp": {
            "type": "integer"
          },
          "allocatedPoints": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "thresholdSelections": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        },
        "required": [
          "affinityType",
          "affinityXp",
          "allocatedPoints",
          "thresholdSelections"
        ]
      },
      "OpenAmmo": {
        "type": "object",
        "properties": {
          "moduleIndex": {
            "type": "integer"
          },
          "ammoType": {
            "type": "string"
          }
        },
        "required": [
          "moduleIndex",
          "ammoType"
        ]
      },
      "OpenSlotOverride": {
        "type": "object",
        "properties": {
          "cell": {
            "type": "integer",
            "description": "The cell index: row x columns + col."
          },
          "slotType": {
            "type": "string"
          }
        },
        "required": [
          "cell",
          "slotType"
        ]
      },
      "OpenFit": {
        "type": "object",
        "description": "A fit written out by name: GUIDs are decimal strings, enums are their names, and fixed-point values are raw decimal strings. A request may leave fields out. The evaluation reads as much of the fit as it can and reports each missing or unreadable part as an `InvalidFit` issue, with status 200 and `valid: false`, instead of rejecting the request.",
        "properties": {
          "version": {
            "type": "integer",
            "description": "Always 1."
          },
          "hull": {
            "$ref": "#/components/schemas/OpenItem"
          },
          "progression": {
            "$ref": "#/components/schemas/OpenProgression"
          },
          "modules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenModule"
            }
          },
          "ammo": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenAmmo"
            }
          },
          "slotOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenSlotOverride"
            }
          }
        },
        "required": [
          "version",
          "hull",
          "progression",
          "modules",
          "ammo",
          "slotOverrides"
        ]
      },
      "FitBody": {
        "type": "object",
        "description": "A fit. Fields you leave out are accepted and reported as issues by the evaluation; see `OpenFit`.",
        "properties": {
          "fit": {
            "$ref": "#/components/schemas/OpenFit"
          }
        },
        "required": [
          "fit"
        ]
      },
      "FitStringBody": {
        "type": "object",
        "properties": {
          "fitString": {
            "type": "string",
            "description": "The game's shareable fit string."
          }
        },
        "required": [
          "fitString"
        ]
      },
      "ItemBody": {
        "type": "object",
        "properties": {
          "item": {
            "$ref": "#/components/schemas/OpenItem"
          }
        },
        "required": [
          "item"
        ]
      },
      "FactsBody": {
        "type": "object",
        "properties": {
          "facts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FactRow"
            }
          }
        },
        "required": [
          "facts"
        ]
      },
      "EvaluationIssue": {
        "type": "object",
        "properties": {
          "moduleIndex": {
            "type": "integer",
            "description": "Index into the fit's modules; -1 when the issue is about the hull or the fit."
          },
          "kind": {
            "type": "string",
            "description": "The kind of issue, such as `SlotNotFittable`. Kinds don't change between builds."
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "moduleIndex",
          "kind",
          "message"
        ]
      },
      "ConduitLink": {
        "type": "object",
        "properties": {
          "moduleIndex": {
            "type": "integer"
          },
          "connectionCount": {
            "type": "integer"
          }
        },
        "required": [
          "moduleIndex",
          "connectionCount"
        ]
      },
      "RegaliaGroup": {
        "type": "object",
        "properties": {
          "set": {
            "type": "string",
            "description": "A regalia set id.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "fittedCount": {
            "type": "integer"
          },
          "moduleIndices": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        },
        "required": [
          "set",
          "fittedCount",
          "moduleIndices"
        ]
      },
      "StatSource": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string"
          },
          "asset": {
            "type": [
              "string",
              "null"
            ],
            "description": "The id of the item or definition behind the source."
          },
          "affinityType": {
            "type": "string"
          },
          "raw": {
            "type": "number"
          },
          "ratio": {
            "type": "number"
          },
          "effective": {
            "type": "number"
          },
          "isStackingExempt": {
            "type": "boolean"
          }
        },
        "required": [
          "kind",
          "asset",
          "affinityType",
          "raw",
          "ratio",
          "effective",
          "isStackingExempt"
        ]
      },
      "StatLine": {
        "type": "object",
        "properties": {
          "stat": {
            "type": "string"
          },
          "stage": {
            "type": "string"
          },
          "operation": {
            "type": "string"
          },
          "total": {
            "type": "number"
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatSource"
            }
          }
        },
        "required": [
          "stat",
          "stage",
          "operation",
          "total",
          "sources"
        ]
      },
      "SpecValue": {
        "type": "object",
        "description": "The game shows `text` followed by `unit`.",
        "properties": {
          "text": {
            "type": "string"
          },
          "unit": {
            "type": "string"
          },
          "number": {
            "type": [
              "number",
              "null"
            ],
            "description": "The shown number in that unit, or null for a word such as STABLE."
          }
        },
        "required": [
          "text",
          "unit",
          "number"
        ]
      },
      "SpecHelp": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "title",
          "text"
        ]
      },
      "SpecRow": {
        "type": "object",
        "description": "A row of the game's hull spec panel.",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "primary": {
            "$ref": "#/components/schemas/SpecValue"
          },
          "secondary": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SpecValue"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present when the row is a comparison: `primary` is the stat before, `secondary` the stat now."
          },
          "primaryTone": {
            "type": "string"
          },
          "secondaryTone": {
            "type": "string"
          },
          "help": {
            "$ref": "#/components/schemas/SpecHelp"
          }
        },
        "required": [
          "id",
          "label",
          "primary",
          "secondary",
          "primaryTone",
          "secondaryTone",
          "help"
        ]
      },
      "SpecSection": {
        "type": "object",
        "description": "A section of the game's hull spec panel, in the panel's order.",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpecRow"
            }
          }
        },
        "required": [
          "id",
          "label",
          "rows"
        ]
      },
      "Evaluation": {
        "type": "object",
        "properties": {
          "buildSha": {
            "type": "string"
          },
          "valid": {
            "type": "boolean",
            "description": "False when `issues` isn't empty."
          },
          "issues": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvaluationIssue"
            }
          },
          "conduits": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConduitLink"
            }
          },
          "regaliaSets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RegaliaGroup"
            }
          },
          "stats": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatLine"
            }
          },
          "rating": {
            "type": "integer"
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpecSection"
            }
          }
        },
        "required": [
          "buildSha",
          "valid",
          "issues",
          "conduits",
          "regaliaSets",
          "stats",
          "rating",
          "sections"
        ]
      },
      "Ability": {
        "type": "object",
        "description": "A battery ability, worded as the game words it (upper case).",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "description"
        ]
      },
      "GrantModifier": {
        "type": "object",
        "description": "A fixed stat modifier a set or piece bonus grants.",
        "properties": {
          "stat": {
            "type": "string",
            "description": "A stat id from `/v1/stats`."
          },
          "operation": {
            "type": "string"
          },
          "value": {
            "type": "string",
            "description": "The value set in the game data, as a raw fixed-point decimal string (divide by 65536), in the stat system's format: a Multiply of 1.45 means +45%. `row.number` holds the same value as the tooltip shows it, unrounded, so a Multiply comes as a percent.",
            "pattern": "^-?[0-9]+$"
          },
          "row": {
            "$ref": "#/components/schemas/FactRow",
            "description": "The line as the item tooltip words it, such as MAX VELOCITY +12.5%."
          }
        },
        "required": [
          "stat",
          "operation",
          "value",
          "row"
        ]
      },
      "GrantEffect": {
        "type": "object",
        "description": "A grant that is not a stat line, worded as the game words it.",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "Triggered",
              "ScaledStat",
              "RuntimeStatRule",
              "PassiveStateTick"
            ],
            "description": "What the text is for each kind. Triggered: the effect's tooltip text. ScaledStat: the rule's tooltip template, which may contain `{value}`. RuntimeStatRule and PassiveStateTick: the rule's description."
          },
          "rule": {
            "type": "string",
            "description": "The rule's asset id.",
            "pattern": "^(0|-?[1-9][0-9]*)$"
          },
          "text": {
            "type": "string"
          },
          "chance": {
            "oneOf": [
              {
                "type": "string",
                "description": "A fixed-point number as a raw decimal string: divide by 65536.",
                "pattern": "^-?[0-9]+$"
              },
              {
                "type": "null"
              }
            ],
            "description": "Triggered only. The grant's chance as fixed point, where 65536 means always."
          },
          "strength": {
            "oneOf": [
              {
                "type": "string",
                "description": "A fixed-point number as a raw decimal string: divide by 65536.",
                "pattern": "^-?[0-9]+$"
              },
              {
                "type": "null"
              }
            ],
            "description": "ScaledStat only: the grant's strength."
          },
          "displayText": {
            "type": "string",
            "description": "The line as the game's tooltip shows it, with its numbers filled in (`EffectGrantText`). A Triggered effect below 100% starts with its chance, such as `65% ...`, and a ScaledStat's `{value}` becomes the number the game shows. The chance is already in the text, so don't add it again."
          },
          "chanceNumber": {
            "type": [
              "number",
              "null"
            ],
            "description": "Triggered only: the chance in `displayText` as a fraction, where 1 means always, exactly as the fixed-point value holds it. Null for the other kinds."
          }
        },
        "required": [
          "kind",
          "rule",
          "text",
          "chance",
          "strength",
          "displayText",
          "chanceNumber"
        ]
      },
      "SetBonus": {
        "type": "object",
        "description": "What a set, or one of its pieces, grants once `pieces` pieces of the set are linked. Only the tiers the game shows are listed, meaning enabled tiers with at least one grant, in order of `pieces`.",
        "properties": {
          "pieces": {
            "type": "integer",
            "description": "2, 3 or 4."
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GrantModifier"
            }
          },
          "effects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GrantEffect"
            }
          }
        },
        "required": [
          "pieces",
          "modifiers",
          "effects"
        ]
      }
    },
    "headers": {
      "Build": {
        "description": "The commit SHA of the build that answered.",
        "schema": {
          "type": "string"
        }
      },
      "ETag": {
        "description": "A strong ETag: the SHA-256 of the response body, or the file name for art. Send it back in `If-None-Match`.",
        "schema": {
          "type": "string"
        }
      },
      "CacheControl": {
        "description": "How long a response may be reused.",
        "schema": {
          "type": "string"
        }
      },
      "Warning": {
        "description": "Sent when the request has no User-Agent or a generic one, with the value `299 - \"Send a User-Agent naming your app and a contact\"`. The request is still served.",
        "schema": {
          "type": "string"
        }
      },
      "RetryAfter": {
        "description": "Whole seconds to wait before retrying.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "CORS": {
        "description": "Always `*`. The API doesn't use credentials.",
        "schema": {
          "type": "string",
          "const": "*"
        }
      }
    },
    "parameters": {
      "ItemId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "An item id: an asset GUID as a decimal string, with no plus sign or leading zeros, that fits in a signed 64-bit integer. Anything else gets a 400.",
        "schema": {
          "type": "string",
          "pattern": "^(0|-?[1-9][0-9]*)$"
        }
      },
      "HullId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "A hull id: an asset GUID as a decimal string, with no plus sign or leading zeros, that fits in a signed 64-bit integer. Anything else gets a 400.",
        "schema": {
          "type": "string",
          "pattern": "^(0|-?[1-9][0-9]*)$"
        }
      },
      "ArtFile": {
        "name": "file",
        "in": "path",
        "required": true,
        "description": "A file name taken from an art URL: lower-case letters, digits and `.` `@` `_` `-`, ending in `.webp`.",
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9.@_-]+\\.webp$"
        }
      },
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "required": false,
        "description": "An ETag from an earlier response. If it still matches, you get a 304.",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Something in the request is malformed: the id, the body or the file name. Code `bad_request`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "NotFound": {
        "description": "Nothing has that id, or the route doesn't exist. Code `not_found`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "TooLarge": {
        "description": "The body is over 256 KB. Code `too_large`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "RateLimited": {
        "description": "This client has used up its rate limit. Wait `Retry-After` seconds. Code `rate_limited`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Starting": {
        "description": "The API is still starting up. Code `starting`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "Internal": {
        "description": "Something failed unexpectedly. Code `internal`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The route doesn't take this method; `Allow` lists the ones it does. Code `bad_request`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          },
          "Allow": {
            "description": "The methods the route takes.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "The body isn't sent as `application/json`. Code `bad_request`.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            }
          }
        }
      },
      "NotModified": {
        "description": "The `If-None-Match` tag still matches, so no body is sent.",
        "headers": {
          "X-Citadel-Build": {
            "$ref": "#/components/headers/Build"
          },
          "Access-Control-Allow-Origin": {
            "$ref": "#/components/headers/CORS"
          },
          "Warning": {
            "$ref": "#/components/headers/Warning"
          },
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControl"
          }
        }
      }
    }
  }
}
