{
  "components": {
    "headers": {
      "ETag": {
        "description": "The brand's `version` as an entity tag (`\"7\"`). Send it back as `If-Match` to make `PUT /brand` conditional.",
        "schema": {
          "type": "string"
        }
      },
      "Idempotent-Replayed": {
        "description": "`true` when this is the stored answer to an earlier request with the same `Idempotency-Key` and the same request: nothing was done again. Absent on a first answer. Any answer below 500 is stored for 24 hours, so a replayed problem carries it too.",
        "schema": {
          "enum": [
            "true"
          ],
          "type": "string"
        }
      },
      "Location": {
        "description": "The operation to poll: `/api/v1/operations/{id}`, with the `id` of the operation in the body.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before retrying. Sent with `rate_limited`, `idempotency_request_in_progress`, `unavailable` and the other answers a retry can cure; absent when retrying will not help.",
        "schema": {
          "minimum": 0,
          "type": "integer"
        }
      },
      "WWW-Authenticate": {
        "description": "`Bearer`: the authentication scheme this API takes.",
        "schema": {
          "type": "string"
        }
      },
      "X-Request-ID": {
        "description": "The request's id: the caller's own `X-Request-ID` when it is 1-64 letters, digits, `.`, `_`, `:` or `-`, a new one otherwise. A problem repeats it as `request_id`, and the audit log records it.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "AiGateway": {
        "description": "The platform's AI gateway: one OpenAI-compatible endpoint in front of\nevery served model, called with a virtual key.",
        "properties": {
          "base_url": {
            "description": "The OpenAI-compatible base URL clients call (ends in `/v1`), with `Authorization: Bearer <key>`. From the same gateway credential the keys are minted against.",
            "title": "Base Url",
            "type": "string"
          },
          "tiers": {
            "description": "Every serving tier name in the catalogue, sorted.",
            "items": {
              "type": "string"
            },
            "title": "Tiers",
            "type": "array"
          }
        },
        "required": [
          "base_url",
          "tiers"
        ],
        "title": "AiGateway",
        "type": "object"
      },
      "AiModel": {
        "description": "A model of the AI model catalogue: what it is (the metadata a client may\nset) and where its weights are (read-only, set by the store actions). A row\nexists whether or not any weights are present.",
        "properties": {
          "architecture": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's architecture, as recorded: `dense` or `moe` (mixture of experts). Other values may appear.",
            "title": "Architecture"
          },
          "benchmarks": {
            "anyOf": [
              {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "format": "double",
                      "type": "number"
                    },
                    {
                      "type": "integer"
                    },
                    {
                      "type": "string"
                    }
                  ]
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Published benchmark scores: benchmark name to score, e.g. `{\"SWE-bench Verified\": 69.6}`. As published by the vendor; not measured here.",
            "title": "Benchmarks"
          },
          "category": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is for: `coding`, `agentic`, `reasoning`, `vision`, `embedding`, `rerank`, `general`, `speech` or `video`. Other values may appear.",
            "title": "Category"
          },
          "context_window": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The context window in human form, as recorded, e.g. `128K` or `256K→1M`.",
            "title": "Context Window"
          },
          "created_at": {
            "description": "When the model entered the catalogue.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A longer introduction, for the model's detail view.",
            "title": "Description"
          },
          "dgx_recipe": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The serving recipe a DGX cluster runs it with, if any.",
            "title": "Dgx Recipe"
          },
          "display_name": {
            "description": "The name the catalogue shows. On create it defaults to the last part of `repo`.",
            "title": "Display Name",
            "type": "string"
          },
          "frontier_equiv": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which hosted frontier model it is roughly comparable to, and from when, in a few words. An estimate, not a measurement.",
            "title": "Frontier Equiv"
          },
          "gated": {
            "description": "The Hugging Face repo needs an accept-click (access approval) before a pull.",
            "title": "Gated",
            "type": "boolean"
          },
          "gateway_tier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The AI gateway serving tier the model is meant for, e.g. `code` or `general` (`GET /ai/gateway/tiers`). Recorded only: which model backs a tier is decided there, not here.",
            "title": "Gateway Tier"
          },
          "id": {
            "description": "The model's id in the catalogue.",
            "title": "Id",
            "type": "string"
          },
          "license": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's licence, as recorded, e.g. `Apache-2.0`, `MIT`.",
            "title": "License"
          },
          "location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only: set by the store actions (pull, node cache, purge), never by a client. Where the weights are. `synology`: the central model store; `local`: node caches only; `both`: the central model store and at least one node cache; null: nowhere yet. Other values may appear.",
            "title": "Location"
          },
          "min_target": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The smallest hardware it runs on, in human form, e.g. `1× 3090` or `2×DGX`.",
            "title": "Min Target"
          },
          "model_card_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model card's web address.",
            "title": "Model Card Url"
          },
          "nas_path": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the central copy is; null without one.",
            "title": "Nas Path"
          },
          "nas_volume": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only: set by the store actions (pull, node cache, purge), never by a client. The central-store share holding the weights; null while there is no central copy.",
            "title": "Nas Volume"
          },
          "node_caches": {
            "description": "The node caches (see /node-caches).",
            "items": {
              "$ref": "#/components/schemas/NodeCacheRef"
            },
            "title": "Node Caches",
            "type": "array"
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-form notes of the platform's operators.",
            "title": "Notes"
          },
          "offline_ready": {
            "description": "Read-only: set by the store actions (pull, node cache, purge), never by a client. A node holds a cached copy.",
            "title": "Offline Ready",
            "type": "boolean"
          },
          "org": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Hugging Face organisation the repo is published under. It may be a quantizer rather than the lab that built the model (that is `vendor`).",
            "title": "Org"
          },
          "param_count_b": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in billions, as a number to sort by.",
            "title": "Param Count B"
          },
          "params": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in human form, e.g. \"480B (35B active)\".",
            "title": "Params"
          },
          "published": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the model was released upstream, as recorded, e.g. `2024-11`.",
            "title": "Published"
          },
          "quant": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' precision or quantisation, as recorded, e.g. `BF16`, `FP8`, `AWQ`, `NVFP4`.",
            "title": "Quant"
          },
          "repo": {
            "description": "A Hugging Face repo id `org/name`: each part starts with a letter or digit and holds only letters, digits, `.`, `_` and `-` (no `..`), at most 96 characters. Frozen after create.",
            "title": "Repo",
            "type": "string"
          },
          "serving_node": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the model is meant to be served: an AI node's hostname or a DGX cluster, as recorded. Recorded only: loading a model is not part of this API.",
            "title": "Serving Node"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' size on disk in GB, as recorded.",
            "title": "Size Gb"
          },
          "status": {
            "description": "Read-only: set by the store actions (pull, node cache, purge), never by a client. `planned` (recorded, no weights yet), `pulling` (a copy into the central store is running), `owned` (the weights are in the central store) or `serving` (a node serves it). Other values may appear.",
            "title": "Status",
            "type": "string"
          },
          "strong_axis": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is strongest at, in a few words, e.g. `agentic coding`.",
            "title": "Strong Axis"
          },
          "summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A one-line introduction, for a catalogue card.",
            "title": "Summary"
          },
          "updated_at": {
            "description": "The last change to the row, by a client or by a store action; equal to `created_at` until the first change.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          },
          "vendor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The lab that built the model. The Hugging Face organisation (`org`) may be a quantizer.",
            "title": "Vendor"
          },
          "vendor_country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The vendor's home country, as recorded, e.g. `China`, `France`, `USA`.",
            "title": "Vendor Country"
          }
        },
        "required": [
          "id",
          "repo",
          "display_name",
          "gated",
          "status",
          "location",
          "offline_ready",
          "nas_volume",
          "nas_path",
          "dgx_recipe",
          "node_caches",
          "created_at",
          "updated_at"
        ],
        "title": "AiModel",
        "type": "object"
      },
      "AiModelCreate": {
        "additionalProperties": false,
        "description": "A catalogue row. The model is created `planned`, with no central copy and\nno node cache: weights arrive only through the store actions, and pulling\nthem is not part of v1. `display_name` defaults to the repo's last part.",
        "properties": {
          "architecture": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's architecture, as recorded: `dense` or `moe` (mixture of experts). Other values may appear.",
            "title": "Architecture"
          },
          "benchmarks": {
            "anyOf": [
              {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "format": "double",
                      "type": "number"
                    },
                    {
                      "type": "integer"
                    },
                    {
                      "type": "string"
                    }
                  ]
                },
                "maxProperties": 100,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Published benchmark scores: benchmark name to score, e.g. `{\"SWE-bench Verified\": 69.6}`. As published by the vendor; not measured here.",
            "title": "Benchmarks"
          },
          "category": {
            "anyOf": [
              {
                "maxLength": 24,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is for: `coding`, `agentic`, `reasoning`, `vision`, `embedding`, `rerank`, `general`, `speech` or `video`. Other values may appear.",
            "title": "Category"
          },
          "context_window": {
            "anyOf": [
              {
                "maxLength": 20,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The context window in human form, as recorded, e.g. `128K` or `256K→1M`.",
            "title": "Context Window"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 20000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A longer introduction, for the model's detail view.",
            "title": "Description"
          },
          "display_name": {
            "anyOf": [
              {
                "maxLength": 255,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name the catalogue shows. On create it defaults to the last part of `repo`.",
            "title": "Display Name"
          },
          "frontier_equiv": {
            "anyOf": [
              {
                "maxLength": 120,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which hosted frontier model it is roughly comparable to, and from when, in a few words. An estimate, not a measurement.",
            "title": "Frontier Equiv"
          },
          "gated": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Hugging Face repo needs an accept-click (access approval) before a pull.",
            "title": "Gated"
          },
          "gateway_tier": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The AI gateway serving tier the model is meant for, e.g. `code` or `general` (`GET /ai/gateway/tiers`). Recorded only: which model backs a tier is decided there, not here.",
            "title": "Gateway Tier"
          },
          "license": {
            "anyOf": [
              {
                "maxLength": 80,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's licence, as recorded, e.g. `Apache-2.0`, `MIT`.",
            "title": "License"
          },
          "min_target": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The smallest hardware it runs on, in human form, e.g. `1× 3090` or `2×DGX`.",
            "title": "Min Target"
          },
          "model_card_url": {
            "anyOf": [
              {
                "maxLength": 300,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model card's web address.",
            "title": "Model Card Url"
          },
          "notes": {
            "anyOf": [
              {
                "maxLength": 20000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-form notes of the platform's operators.",
            "title": "Notes"
          },
          "org": {
            "anyOf": [
              {
                "maxLength": 120,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Hugging Face organisation the repo is published under. It may be a quantizer rather than the lab that built the model (that is `vendor`).",
            "title": "Org"
          },
          "param_count_b": {
            "anyOf": [
              {
                "format": "double",
                "maximum": 9999999.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in billions, as a number to sort by.",
            "title": "Param Count B"
          },
          "params": {
            "anyOf": [
              {
                "maxLength": 60,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in human form, e.g. \"480B (35B active)\".",
            "title": "Params"
          },
          "published": {
            "anyOf": [
              {
                "maxLength": 20,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the model was released upstream, as recorded, e.g. `2024-11`.",
            "title": "Published"
          },
          "quant": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' precision or quantisation, as recorded, e.g. `BF16`, `FP8`, `AWQ`, `NVFP4`.",
            "title": "Quant"
          },
          "repo": {
            "description": "A Hugging Face repo id `org/name`: each part starts with a letter or digit and holds only letters, digits, `.`, `_` and `-` (no `..`), at most 96 characters. Frozen after create; unique.",
            "title": "Repo",
            "type": "string"
          },
          "serving_node": {
            "anyOf": [
              {
                "maxLength": 80,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the model is meant to be served: an AI node's hostname or a DGX cluster, as recorded. Recorded only: loading a model is not part of this API.",
            "title": "Serving Node"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "maximum": 99999999.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' size on disk in GB, as recorded.",
            "title": "Size Gb"
          },
          "strong_axis": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is strongest at, in a few words, e.g. `agentic coding`.",
            "title": "Strong Axis"
          },
          "summary": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A one-line introduction, for a catalogue card.",
            "title": "Summary"
          },
          "vendor": {
            "anyOf": [
              {
                "maxLength": 200,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The lab that built the model. The Hugging Face organisation (`org`) may be a quantizer.",
            "title": "Vendor"
          },
          "vendor_country": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The vendor's home country, as recorded, e.g. `China`, `France`, `USA`.",
            "title": "Vendor Country"
          }
        },
        "required": [
          "repo"
        ],
        "title": "AiModelCreate",
        "type": "object"
      },
      "AiModelPage": {
        "description": "One page of AI models of the catalogue. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/AiModel"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "AiModelPage",
        "type": "object"
      },
      "AiModelPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. Of the metadata: `display_name` and `gated` are not nullable.\n`repo`\nis frozen and `status`, `location`, `offline_ready`,\n`nas_volume` are read-only: each may be sent with its current value\nand nothing else.",
        "properties": {
          "architecture": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's architecture, as recorded: `dense` or `moe` (mixture of experts). Other values may appear.",
            "title": "Architecture"
          },
          "benchmarks": {
            "anyOf": [
              {
                "additionalProperties": {
                  "anyOf": [
                    {
                      "format": "double",
                      "type": "number"
                    },
                    {
                      "type": "integer"
                    },
                    {
                      "type": "string"
                    }
                  ]
                },
                "maxProperties": 100,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "Published benchmark scores: benchmark name to score, e.g. `{\"SWE-bench Verified\": 69.6}`. As published by the vendor; not measured here.",
            "title": "Benchmarks"
          },
          "category": {
            "anyOf": [
              {
                "maxLength": 24,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is for: `coding`, `agentic`, `reasoning`, `vision`, `embedding`, `rerank`, `general`, `speech` or `video`. Other values may appear.",
            "title": "Category"
          },
          "context_window": {
            "anyOf": [
              {
                "maxLength": 20,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The context window in human form, as recorded, e.g. `128K` or `256K→1M`.",
            "title": "Context Window"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 20000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A longer introduction, for the model's detail view.",
            "title": "Description"
          },
          "display_name": {
            "anyOf": [
              {
                "maxLength": 255,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name the catalogue shows. On create it defaults to the last part of `repo`.",
            "title": "Display Name"
          },
          "frontier_equiv": {
            "anyOf": [
              {
                "maxLength": 120,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which hosted frontier model it is roughly comparable to, and from when, in a few words. An estimate, not a measurement.",
            "title": "Frontier Equiv"
          },
          "gated": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Hugging Face repo needs an accept-click (access approval) before a pull.",
            "title": "Gated"
          },
          "gateway_tier": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The AI gateway serving tier the model is meant for, e.g. `code` or `general` (`GET /ai/gateway/tiers`). Recorded only: which model backs a tier is decided there, not here.",
            "title": "Gateway Tier"
          },
          "license": {
            "anyOf": [
              {
                "maxLength": 80,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model's licence, as recorded, e.g. `Apache-2.0`, `MIT`.",
            "title": "License"
          },
          "location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only.",
            "title": "Location"
          },
          "min_target": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The smallest hardware it runs on, in human form, e.g. `1× 3090` or `2×DGX`.",
            "title": "Min Target"
          },
          "model_card_url": {
            "anyOf": [
              {
                "maxLength": 300,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model card's web address.",
            "title": "Model Card Url"
          },
          "nas_volume": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only.",
            "title": "Nas Volume"
          },
          "notes": {
            "anyOf": [
              {
                "maxLength": 20000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-form notes of the platform's operators.",
            "title": "Notes"
          },
          "offline_ready": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only.",
            "title": "Offline Ready"
          },
          "org": {
            "anyOf": [
              {
                "maxLength": 120,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Hugging Face organisation the repo is published under. It may be a quantizer rather than the lab that built the model (that is `vendor`).",
            "title": "Org"
          },
          "param_count_b": {
            "anyOf": [
              {
                "format": "double",
                "maximum": 9999999.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in billions, as a number to sort by.",
            "title": "Param Count B"
          },
          "params": {
            "anyOf": [
              {
                "maxLength": 60,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The parameter count in human form, e.g. \"480B (35B active)\".",
            "title": "Params"
          },
          "published": {
            "anyOf": [
              {
                "maxLength": 20,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the model was released upstream, as recorded, e.g. `2024-11`.",
            "title": "Published"
          },
          "quant": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' precision or quantisation, as recorded, e.g. `BF16`, `FP8`, `AWQ`, `NVFP4`.",
            "title": "Quant"
          },
          "repo": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Repo"
          },
          "serving_node": {
            "anyOf": [
              {
                "maxLength": 80,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the model is meant to be served: an AI node's hostname or a DGX cluster, as recorded. Recorded only: loading a model is not part of this API.",
            "title": "Serving Node"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "maximum": 99999999.0,
                "minimum": 0.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The weights' size on disk in GB, as recorded.",
            "title": "Size Gb"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Read-only.",
            "title": "Status"
          },
          "strong_axis": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the model is strongest at, in a few words, e.g. `agentic coding`.",
            "title": "Strong Axis"
          },
          "summary": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A one-line introduction, for a catalogue card.",
            "title": "Summary"
          },
          "vendor": {
            "anyOf": [
              {
                "maxLength": 200,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The lab that built the model. The Hugging Face organisation (`org`) may be a quantizer.",
            "title": "Vendor"
          },
          "vendor_country": {
            "anyOf": [
              {
                "maxLength": 40,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The vendor's home country, as recorded, e.g. `China`, `France`, `USA`.",
            "title": "Vendor Country"
          }
        },
        "title": "AiModelPatch",
        "type": "object"
      },
      "AiNode": {
        "description": "One AI node. The ROSTER fields (from the portal's hardware inventory) are\nalways present; the LIVE fields come from monitoring and are null when it\ncannot be read — this read never fails because of monitoring.",
        "properties": {
          "cluster": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/NodeCluster"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false."
          },
          "collector_stale": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. The node's metrics collector has not reported for more than 30 seconds, so its model and GPU figures may be out of date.",
            "title": "Collector Stale"
          },
          "cpu_util_pct": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. CPU use over the last minute, 0-100.",
            "title": "Cpu Util Pct"
          },
          "disk_used_pct": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. Root file system in use, 0-100.",
            "title": "Disk Used Pct"
          },
          "gpu_class": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "e.g. `rtx-3090`, `gb10`, `rtx-pro-6000`.",
            "title": "Gpu Class"
          },
          "gpu_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. GPUs reporting; also null when none does.",
            "title": "Gpu Count"
          },
          "gpu_temp_max_c": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. The hottest GPU's temperature, in °C.",
            "title": "Gpu Temp Max C"
          },
          "gpu_util_avg_pct": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. Average GPU use across the node's GPUs, 0-100.",
            "title": "Gpu Util Avg Pct"
          },
          "hostname": {
            "description": "The node's hostname: its id here.",
            "title": "Hostname",
            "type": "string"
          },
          "is_virtual": {
            "description": "A GPU VM on a hybrid host (its power belongs to `parent_host`).",
            "title": "Is Virtual",
            "type": "boolean"
          },
          "load1": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. The one-minute load average.",
            "title": "Load1"
          },
          "mem_used_pct": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. Memory in use, 0-100.",
            "title": "Mem Used Pct"
          },
          "mgmt_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The node's management address, as the hardware inventory records it.",
            "title": "Mgmt Ip"
          },
          "models": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/NodeModel"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. Loaded models.",
            "title": "Models"
          },
          "monitoring_reachable": {
            "description": "Monitoring reachable: false when monitoring could not be read, and every live field of this node is then null.",
            "title": "Monitoring Reachable",
            "type": "boolean"
          },
          "online": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false.",
            "title": "Online"
          },
          "parent_host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "For a virtual node, the host it runs on; null otherwise.",
            "title": "Parent Host"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. The node's role as monitoring labels it, e.g. `ai-rtx`, `ai-epyc`, `ai-k8s`; null when it carries none. Other values may appear.",
            "title": "Role"
          },
          "services": {
            "description": "Other user-facing services the node hosts (they go offline with it): those seen answering, plus those the inventory declares.",
            "items": {
              "type": "string"
            },
            "title": "Services",
            "type": "array"
          },
          "site": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The site the node is at, as the hardware inventory records it.",
            "title": "Site"
          },
          "specs_summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "CPU, GPUs and memory in one line, from the hardware inventory.",
            "title": "Specs Summary"
          },
          "status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. `serving`, `loaded_idle`, `idle`, `offline`, `standby` or `powered_off`.",
            "title": "Status"
          },
          "throttle_active": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. A GPU is throttling its clock (for power or heat).",
            "title": "Throttle Active"
          },
          "uptime_seconds": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. Seconds since the node booted.",
            "title": "Uptime Seconds"
          },
          "vmid": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "For a virtual node, its VM id on `parent_host`; null otherwise.",
            "title": "Vmid"
          },
          "vram_total_bytes": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. GPU memory in total, in bytes, summed over the GPUs.",
            "title": "Vram Total Bytes"
          },
          "vram_used_bytes": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Live (monitoring); null when `monitoring_reachable` is false. GPU memory in use, in bytes, summed over the GPUs (unified memory on `gb10`).",
            "title": "Vram Used Bytes"
          }
        },
        "required": [
          "hostname",
          "is_virtual",
          "monitoring_reachable"
        ],
        "title": "AiNode",
        "type": "object"
      },
      "AiNodePage": {
        "description": "One page of AI nodes. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/AiNode"
            },
            "title": "Items",
            "type": "array"
          },
          "monitoring_reachable": {
            "description": "Monitoring reachable: false means every live field below is null.",
            "title": "Monitoring Reachable",
            "type": "boolean"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items",
          "monitoring_reachable"
        ],
        "title": "AiNodePage",
        "type": "object"
      },
      "ApiWarning": {
        "description": "Something that did not go as planned, on a request that still succeeded\n— e.g. the customer was created but its GitLab group was not. A client must\nsurface these (the provider reports them as diagnostics).",
        "properties": {
          "code": {
            "description": "The stable, machine-readable reason, e.g. `gitlab_group_failed`. Each operation names the warnings it can give.",
            "title": "Code",
            "type": "string"
          },
          "message": {
            "description": "What happened, for a person. The wording may change.",
            "title": "Message",
            "type": "string"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "title": "ApiWarning",
        "type": "object"
      },
      "AuditEvent": {
        "description": "One change: who made it, what it touched, how they signed in and from where.",
        "properties": {
          "action": {
            "description": "What was done, e.g. `user.create`, `api_v1.post`.",
            "title": "Action",
            "type": "string"
          },
          "actor": {
            "description": "Who made the change: the person's e-mail address as it was at the time, or `system`, `pipeline:<run id>`, `ops:<script>` for automated writers.",
            "title": "Actor",
            "type": "string"
          },
          "after_state": {
            "description": "The entity after the change as the writer recorded it: usually an object, null on a delete. Every member whose NAME looks secret (it contains `secret`, `password`, `token`, `hash`, `pepper`, `credential`, `api_key` and the like, at any depth) is always null here, whatever it held.",
            "title": "After State"
          },
          "auth_kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`session`, `pat` (personal API token) or `service_account`. Null when the writer did not record it: every row older than the public API, and today most portal pages and automated writers (only `/api/v1`, API-token management and platform settings record it).",
            "title": "Auth Kind"
          },
          "before_state": {
            "description": "The entity before the change as the writer recorded it: usually an object, null on a create. Every member whose NAME looks secret (it contains `secret`, `password`, `token`, `hash`, `pepper`, `credential`, `api_key` and the like, at any depth) is always null here, whatever it held.",
            "title": "Before State"
          },
          "entity_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which one, as the writer spelled its id. For `entity_type` `licence` this is the licence serial, masked to its last group (`ATAILA-XXXXX-XXXXX-XXXXX-XXXXX-5F8N5`) unless the caller holds `licence-admin-global`, exactly as on `GET /licence`.",
            "title": "Entity Id"
          },
          "entity_type": {
            "description": "The kind of thing changed, e.g. `users`, `project`.",
            "title": "Entity Type",
            "type": "string"
          },
          "id": {
            "description": "The event's id: a string holding a positive integer. Ids grow with time but are not a clock; order by `occurred_at`.",
            "title": "Id",
            "type": "string"
          },
          "occurred_at": {
            "description": "When the change was recorded.",
            "format": "date-time",
            "title": "Occurred At",
            "type": "string"
          },
          "request_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The request's `X-Request-ID`, when recorded.",
            "title": "Request Id"
          },
          "source_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The client address as the portal saw it, when recorded.",
            "title": "Source Ip"
          },
          "token_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The API token used, when `auth_kind` is `pat` or `service_account`.",
            "title": "Token Id"
          }
        },
        "required": [
          "id",
          "occurred_at",
          "actor",
          "action",
          "entity_type",
          "entity_id",
          "auth_kind",
          "token_id",
          "request_id",
          "source_ip"
        ],
        "title": "AuditEvent",
        "type": "object"
      },
      "AuditEventPage": {
        "description": "One page of audit events. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/AuditEvent"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "AuditEventPage",
        "type": "object"
      },
      "Brand": {
        "description": "The brand as stored. `PUT /brand` replaces every field of this object\nexcept the read-only `first_party`, `attribution`, `version` and\n`updated_at`: to change one field, send all of them back as read here.",
        "properties": {
          "attribution": {
            "description": "Read-only. The line printed under the product name; computed from `first_party`, never stored and never settable.",
            "readOnly": true,
            "title": "Attribution",
            "type": "string"
          },
          "brand_color": {
            "description": "Six-digit hex colour; returned lower-case.",
            "pattern": "^#[0-9a-fA-F]{6}$",
            "title": "Brand Color",
            "type": "string"
          },
          "favicon_asset_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A brand asset of kind `favicon`; null keeps the built-in one. In a `PUT`, null is a value that CLEARS the favicon, not \"leave as is\".",
            "title": "Favicon Asset Id"
          },
          "first_party": {
            "description": "Read-only. True only on ATAILA's own portal; selects the attribution line. No request can change it.",
            "readOnly": true,
            "title": "First Party",
            "type": "boolean"
          },
          "logo_asset_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A brand asset of kind `logo`; null shows the built-in logo. In a `PUT`, null is a value that CLEARS the logo, not \"leave as is\".",
            "title": "Logo Asset Id"
          },
          "logo_offset_x": {
            "description": "Horizontal nudge of the logo, in pixels.",
            "maximum": 40.0,
            "minimum": -40.0,
            "title": "Logo Offset X",
            "type": "integer"
          },
          "logo_size": {
            "description": "The sidebar logo size preset.",
            "enum": [
              "compact",
              "medium",
              "regular",
              "large"
            ],
            "title": "Logo Size",
            "type": "string"
          },
          "page_title": {
            "description": "The browser-tab title.",
            "maxLength": 60,
            "minLength": 1,
            "title": "Page Title",
            "type": "string"
          },
          "product_name": {
            "description": "The wordmark in the sidebar and on the sign-in page.",
            "maxLength": 32,
            "minLength": 2,
            "title": "Product Name",
            "type": "string"
          },
          "product_name_accent": {
            "description": "A part of `product_name` rendered in `brand_color`. Empty colours the whole name.",
            "maxLength": 32,
            "title": "Product Name Accent",
            "type": "string"
          },
          "updated_at": {
            "description": "When the brand was last changed.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          },
          "version": {
            "description": "Bumped by every change; send it back in `If-Match`.",
            "title": "Version",
            "type": "integer"
          }
        },
        "required": [
          "product_name",
          "product_name_accent",
          "brand_color",
          "page_title",
          "logo_size",
          "logo_offset_x",
          "logo_asset_id",
          "favicon_asset_id",
          "first_party",
          "version",
          "updated_at",
          "attribution"
        ],
        "title": "Brand",
        "type": "object"
      },
      "BrandAsset": {
        "description": "An uploaded logo or favicon. An asset is addressed by its content: the\nsame file uploaded twice is one asset.",
        "properties": {
          "bytes": {
            "description": "The file's size in bytes.",
            "title": "Bytes",
            "type": "integer"
          },
          "filename": {
            "description": "The file name given at upload, kept for display only; may be empty.",
            "title": "Filename",
            "type": "string"
          },
          "height": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Height in pixels; null for an SVG.",
            "title": "Height"
          },
          "id": {
            "description": "The asset's id; `logo_asset_id` and `favicon_asset_id` name it.",
            "title": "Id",
            "type": "string"
          },
          "kind": {
            "description": "What the asset is for: a `logo` or a `favicon`.",
            "enum": [
              "logo",
              "favicon"
            ],
            "title": "Kind",
            "type": "string"
          },
          "mime": {
            "description": "The file's type, read from its bytes: `image/png`, `image/webp` or `image/svg+xml` for a logo; `image/png`, `image/svg+xml` or `image/x-icon` for a favicon.",
            "title": "Mime",
            "type": "string"
          },
          "sha256": {
            "description": "The SHA-256 of the file's bytes, in lowercase hex.",
            "title": "Sha256",
            "type": "string"
          },
          "uploaded_at": {
            "description": "When the file was first uploaded.",
            "format": "date-time",
            "title": "Uploaded At",
            "type": "string"
          },
          "url": {
            "description": "Where the asset is served, without a file extension (`/api/brand/assets/<sha256>`); readable without signing in, like the sign-in page itself.",
            "title": "Url",
            "type": "string"
          },
          "width": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Width in pixels; null for an SVG.",
            "title": "Width"
          }
        },
        "required": [
          "id",
          "kind",
          "sha256",
          "mime",
          "bytes",
          "filename",
          "url",
          "uploaded_at"
        ],
        "title": "BrandAsset",
        "type": "object"
      },
      "BrandAssetPage": {
        "description": "One page of brand assets. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/BrandAsset"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "BrandAssetPage",
        "type": "object"
      },
      "BrandAssetUpload": {
        "additionalProperties": false,
        "description": "The JSON form of an upload. Multipart (`file` + `kind`), as the portal\nscreen sends, is accepted on the same operation.",
        "properties": {
          "content_base64": {
            "description": "The file, standard base64; at most 512 KB decoded. Its type is read from the bytes; no content type is sent.",
            "maxLength": 699058,
            "minLength": 1,
            "title": "Content Base64",
            "type": "string"
          },
          "filename": {
            "default": "",
            "description": "The original file name, kept for display only: the asset is addressed by its content (`sha256`).",
            "maxLength": 200,
            "title": "Filename",
            "type": "string"
          },
          "kind": {
            "description": "What the asset is for: a `logo` or a `favicon`.",
            "enum": [
              "logo",
              "favicon"
            ],
            "title": "Kind",
            "type": "string"
          }
        },
        "required": [
          "kind",
          "content_base64"
        ],
        "title": "BrandAssetUpload",
        "type": "object"
      },
      "BrandPut": {
        "additionalProperties": false,
        "description": "FULL REPLACEMENT of the v1 fields, never a partial update: every member\nis required. A member that is missing is refused with 422\n`validation_failed` naming it in `field` (and in `errors`), so nothing is\never reset by omission; `null` for an asset id is a value and clears that\nasset. Send back every field of `GET /brand`, changed or not. Extra\nmembers — `attribution` and `first_party` among them — are refused with\n422.",
        "properties": {
          "brand_color": {
            "description": "Six-digit hex colour; returned lower-case.",
            "pattern": "^#[0-9a-fA-F]{6}$",
            "title": "Brand Color",
            "type": "string"
          },
          "favicon_asset_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A brand asset of kind `favicon`; null keeps the built-in one. In a `PUT`, null is a value that CLEARS the favicon, not \"leave as is\".",
            "title": "Favicon Asset Id"
          },
          "logo_asset_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A brand asset of kind `logo`; null shows the built-in logo. In a `PUT`, null is a value that CLEARS the logo, not \"leave as is\".",
            "title": "Logo Asset Id"
          },
          "logo_offset_x": {
            "description": "Horizontal nudge of the logo, in pixels.",
            "maximum": 40.0,
            "minimum": -40.0,
            "title": "Logo Offset X",
            "type": "integer"
          },
          "logo_size": {
            "description": "The sidebar logo size preset.",
            "enum": [
              "compact",
              "medium",
              "regular",
              "large"
            ],
            "title": "Logo Size",
            "type": "string"
          },
          "page_title": {
            "description": "The browser-tab title.",
            "maxLength": 60,
            "minLength": 1,
            "title": "Page Title",
            "type": "string"
          },
          "product_name": {
            "description": "The wordmark in the sidebar and on the sign-in page.",
            "maxLength": 32,
            "minLength": 2,
            "title": "Product Name",
            "type": "string"
          },
          "product_name_accent": {
            "description": "A part of `product_name` rendered in `brand_color`. Empty colours the whole name.",
            "maxLength": 32,
            "title": "Product Name Accent",
            "type": "string"
          }
        },
        "required": [
          "product_name",
          "product_name_accent",
          "brand_color",
          "page_title",
          "logo_size",
          "logo_offset_x",
          "logo_asset_id",
          "favicon_asset_id"
        ],
        "title": "BrandPut",
        "type": "object"
      },
      "CachedModelRef": {
        "description": "A model with a complete copy on the node.",
        "properties": {
          "cached_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the copy was last made or checked.",
            "title": "Cached At"
          },
          "name": {
            "description": "The model's `display_name`.",
            "title": "Name",
            "type": "string"
          },
          "repo": {
            "description": "The model's Hugging Face repo id.",
            "title": "Repo",
            "type": "string"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The copy's size on the node's disk in GB, when measured.",
            "title": "Size Gb"
          }
        },
        "required": [
          "name",
          "repo"
        ],
        "title": "CachedModelRef",
        "type": "object"
      },
      "ClusterMember": {
        "description": "A node of a DGX cluster.",
        "properties": {
          "crosslink_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The member's address on the cluster's own interconnect (`crosslink_subnet`).",
            "title": "Crosslink Ip"
          },
          "hostname": {
            "description": "The member's hostname.",
            "title": "Hostname",
            "type": "string"
          },
          "mgmt_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The member's management address.",
            "title": "Mgmt Ip"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`head` or `worker`. Other values may appear.",
            "title": "Role"
          }
        },
        "required": [
          "hostname"
        ],
        "title": "ClusterMember",
        "type": "object"
      },
      "ClusterServe": {
        "description": "What a DGX cluster serves, as recorded when serving was started.",
        "properties": {
          "model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model it serves.",
            "title": "Model"
          },
          "recipe": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The serving recipe the cluster runs, by name.",
            "title": "Recipe"
          },
          "served_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When serving started, if recorded (a value that is not a timestamp reads as null).",
            "title": "Served At"
          }
        },
        "title": "ClusterServe",
        "type": "object"
      },
      "Customer": {
        "description": "A company on this platform. It owns tenants, and through them projects.",
        "properties": {
          "billing_tier": {
            "description": "`INTERNAL`: not invoiced (ATAILA's own and reference customers); `PAYING`: invoiced.",
            "enum": [
              "INTERNAL",
              "PAYING"
            ],
            "title": "Billing Tier",
            "type": "string"
          },
          "created_at": {
            "description": "When the customer was registered.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "customer_index": {
            "description": "The customer's number on this platform, 1-999; unique, archived customers included. Frozen.",
            "title": "Customer Index",
            "type": "integer"
          },
          "default_email_tier": {
            "description": "The mail service the customer's mailboxes are created on by default: `1`, `2` or `3`, as the portal's customer page names them.",
            "title": "Default Email Tier",
            "type": "integer"
          },
          "edition": {
            "description": "`sp` (the default): a customer of this multi-tenant platform; `enterprise`: a customer with a single-tenant installation of its own. Frozen.",
            "enum": [
              "sp",
              "enterprise"
            ],
            "title": "Edition",
            "type": "string"
          },
          "gitlab_group": {
            "description": "The customer's top-level GitLab group; also its primary tenant's slug. Frozen.",
            "title": "Gitlab Group",
            "type": "string"
          },
          "gitlab_status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/GitLabGroupStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Only with `?include=gitlab_status` on a read; null when GitLab could not be asked (a warning then says why)."
          },
          "id": {
            "description": "The customer's id.",
            "title": "Id",
            "type": "string"
          },
          "long_name": {
            "description": "The customer's full name.",
            "title": "Long Name",
            "type": "string"
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text for operators, up to 2000 characters.",
            "title": "Notes"
          },
          "primary_contact_email": {
            "description": "An e-mail address. Stored and returned normalised: the domain is lower-cased (and internationalised domains are converted to their canonical form), the local part (before `@`) keeps its case exactly as sent, surrounding whitespace is dropped, and a `Name <address>` form is reduced to the address. `Pat@Example.COM` is therefore returned as `Pat@example.com`; compare with the domain case-folded to avoid a perpetual diff.",
            "title": "Primary Contact Email",
            "type": "string"
          },
          "primary_contact_name": {
            "description": "The name of the customer's primary contact.",
            "title": "Primary Contact Name",
            "type": "string"
          },
          "primary_tenant_id": {
            "description": "The tenant created with the customer; it can never be deleted.",
            "title": "Primary Tenant Id",
            "type": "string"
          },
          "short_name": {
            "description": "Upper-case letters and digits, e.g. `ACME`; unique, archived customers included. Frozen.",
            "title": "Short Name",
            "type": "string"
          },
          "status": {
            "description": "`active`, `suspended` or `archived`. `archived` is set only by `DELETE /customers/{id}` and is final: v1 has no way to restore an archived customer.",
            "enum": [
              "active",
              "suspended",
              "archived"
            ],
            "title": "Status",
            "type": "string"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          }
        },
        "required": [
          "id",
          "customer_index",
          "short_name",
          "long_name",
          "gitlab_group",
          "edition",
          "primary_tenant_id",
          "primary_contact_email",
          "primary_contact_name",
          "default_email_tier",
          "billing_tier",
          "status",
          "created_at"
        ],
        "title": "Customer",
        "type": "object"
      },
      "CustomerCreate": {
        "additionalProperties": false,
        "description": "A new customer. Its primary tenant (slug = `gitlab_group`) is created with\nit, and its GitLab group is created or adopted.",
        "properties": {
          "billing_tier": {
            "default": "INTERNAL",
            "description": "`INTERNAL`: not invoiced (ATAILA's own and reference customers); `PAYING`: invoiced. Default `INTERNAL`.",
            "enum": [
              "INTERNAL",
              "PAYING"
            ],
            "title": "Billing Tier",
            "type": "string"
          },
          "customer_index": {
            "anyOf": [
              {
                "maximum": 999.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Omit to have the server allocate the next free index.",
            "title": "Customer Index"
          },
          "default_email_tier": {
            "default": 3,
            "description": "The mail service the customer's mailboxes are created on by default: `1`, `2` or `3`, as the portal's customer page names them. Default `3`.",
            "enum": [
              1,
              2,
              3
            ],
            "title": "Default Email Tier",
            "type": "integer"
          },
          "edition": {
            "default": "sp",
            "description": "`sp` (the default): a customer of this multi-tenant platform; `enterprise`: a customer with a single-tenant installation of its own. Frozen after create.",
            "enum": [
              "sp",
              "enterprise"
            ],
            "title": "Edition",
            "type": "string"
          },
          "gitlab_group": {
            "description": "Also the primary tenant's slug, so the tenant slug rule applies: Lowercase letters, digits and '-', starting with a letter, 2-30 characters. Frozen after create.",
            "pattern": "^[a-z][a-z0-9-]{1,29}$",
            "title": "Gitlab Group",
            "type": "string"
          },
          "long_name": {
            "description": "The customer's full name.",
            "maxLength": 80,
            "minLength": 3,
            "title": "Long Name",
            "type": "string"
          },
          "notes": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text for operators, up to 2000 characters.",
            "title": "Notes"
          },
          "primary_contact_email": {
            "description": "An e-mail address. Stored and returned normalised: the domain is lower-cased (and internationalised domains are converted to their canonical form), the local part (before `@`) keeps its case exactly as sent, surrounding whitespace is dropped, and a `Name <address>` form is reduced to the address. `Pat@Example.COM` is therefore returned as `Pat@example.com`; compare with the domain case-folded to avoid a perpetual diff.",
            "format": "email",
            "title": "Primary Contact Email",
            "type": "string"
          },
          "primary_contact_name": {
            "description": "The name of the customer's primary contact.",
            "maxLength": 80,
            "minLength": 2,
            "title": "Primary Contact Name",
            "type": "string"
          },
          "short_name": {
            "description": "Upper-case letters and digits, starting with a letter, 2-16 characters (e.g. `ACME`). Frozen after create.",
            "maxLength": 16,
            "minLength": 2,
            "pattern": "^[A-Z][A-Z0-9]{1,15}$",
            "title": "Short Name",
            "type": "string"
          },
          "status": {
            "default": "active",
            "description": "`active` (default) or `suspended`.",
            "enum": [
              "active",
              "suspended"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "short_name",
          "long_name",
          "gitlab_group",
          "primary_contact_email",
          "primary_contact_name"
        ],
        "title": "CustomerCreate",
        "type": "object"
      },
      "CustomerPage": {
        "description": "One page of customers. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/Customer"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "CustomerPage",
        "type": "object"
      },
      "CustomerPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. Only `notes` is nullable.\n`archived` is not a settable status: archiving is\n`DELETE /customers/{id}`.",
        "properties": {
          "billing_tier": {
            "anyOf": [
              {
                "enum": [
                  "INTERNAL",
                  "PAYING"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`INTERNAL`: not invoiced (ATAILA's own and reference customers); `PAYING`: invoiced.",
            "title": "Billing Tier"
          },
          "customer_index": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Customer Index"
          },
          "default_email_tier": {
            "anyOf": [
              {
                "enum": [
                  1,
                  2,
                  3
                ],
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The mail service the customer's mailboxes are created on by default: `1`, `2` or `3`, as the portal's customer page names them.",
            "title": "Default Email Tier"
          },
          "edition": {
            "anyOf": [
              {
                "enum": [
                  "sp",
                  "enterprise"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Edition"
          },
          "gitlab_group": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Gitlab Group"
          },
          "long_name": {
            "anyOf": [
              {
                "maxLength": 80,
                "minLength": 3,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The customer's full name.",
            "title": "Long Name"
          },
          "notes": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text for operators, up to 2000 characters. null clears it.",
            "title": "Notes"
          },
          "primary_contact_email": {
            "anyOf": [
              {
                "format": "email",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "An e-mail address. Stored and returned normalised: the domain is lower-cased (and internationalised domains are converted to their canonical form), the local part (before `@`) keeps its case exactly as sent, surrounding whitespace is dropped, and a `Name <address>` form is reduced to the address. `Pat@Example.COM` is therefore returned as `Pat@example.com`; compare with the domain case-folded to avoid a perpetual diff.",
            "title": "Primary Contact Email"
          },
          "primary_contact_name": {
            "anyOf": [
              {
                "maxLength": 80,
                "minLength": 2,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name of the customer's primary contact.",
            "title": "Primary Contact Name"
          },
          "short_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Short Name"
          },
          "status": {
            "anyOf": [
              {
                "enum": [
                  "active",
                  "suspended"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`active` or `suspended`; archiving is `DELETE /customers/{id}`.",
            "title": "Status"
          }
        },
        "title": "CustomerPatch",
        "type": "object"
      },
      "DgxCluster": {
        "description": "DGX nodes joined into one serving pool, as recorded. A DGX in no cluster\nserves on its own.",
        "properties": {
          "created_at": {
            "description": "When the cluster was defined.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "crosslink_subnet": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The subnet (CIDR) of the members' interconnect addresses.",
            "title": "Crosslink Subnet"
          },
          "error_message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the last change failed, when `status` is `error`.",
            "title": "Error Message"
          },
          "id": {
            "description": "The cluster's id.",
            "title": "Id",
            "type": "string"
          },
          "interconnect": {
            "description": "The interconnect the members share: `direct-cable`, or the switch they are connected through. Other values may appear.",
            "title": "Interconnect",
            "type": "string"
          },
          "members": {
            "description": "The member nodes, head first.",
            "items": {
              "$ref": "#/components/schemas/ClusterMember"
            },
            "title": "Members",
            "type": "array"
          },
          "name": {
            "description": "The cluster's name, unique; a load target names it so.",
            "title": "Name",
            "type": "string"
          },
          "notes": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free-form notes of the platform's operators.",
            "title": "Notes"
          },
          "serve": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ClusterServe"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the cluster serves; null when nothing is recorded."
          },
          "status": {
            "description": "As recorded: `defined`, `forming`, `active`, `breaking` or `error`. This read does not converge a cluster that is mid-change (the portal's DGX page does).",
            "title": "Status",
            "type": "string"
          },
          "topology": {
            "description": "How the members are wired: `pair-direct` (two nodes, cabled to each other), `pair-switch` (two nodes through a switch), `ring3` (three nodes in a ring) or `quad-switch` (four nodes through a switch). Other values may appear.",
            "title": "Topology",
            "type": "string"
          },
          "updated_at": {
            "description": "The last change; equal to `created_at` until the first change.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "topology",
          "interconnect",
          "members",
          "status",
          "created_at",
          "updated_at"
        ],
        "title": "DgxCluster",
        "type": "object"
      },
      "DgxClusterPage": {
        "description": "One page of DGX clusters. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/DgxCluster"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "DgxClusterPage",
        "type": "object"
      },
      "GatewayKey": {
        "description": "An AI gateway virtual key: what one application of one tenant calls the\ngateway with, the tiers it may call and its limits. The key's value is\nnever returned after the request that made it (`secret`).",
        "properties": {
          "app": {
            "description": "Frozen.",
            "title": "App",
            "type": "string"
          },
          "budget_duration": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The soft budget's period, e.g. `30d`.",
            "title": "Budget Duration"
          },
          "created_at": {
            "description": "When the key was created or adopted.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "created_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the user (a person or a service account) who created or adopted the key; null when not recorded.",
            "title": "Created By"
          },
          "env": {
            "description": "Frozen.",
            "enum": [
              "dev",
              "uat",
              "prod"
            ],
            "title": "Env",
            "type": "string"
          },
          "feature": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Feature"
          },
          "id": {
            "description": "The key's id (a UUID).",
            "title": "Id",
            "type": "string"
          },
          "key_alias": {
            "description": "`<organisation-slug>-<env>-<app>[-<feature>]` for a key created here; an adopted key keeps the alias it had. Unique among live keys.",
            "title": "Key Alias",
            "type": "string"
          },
          "live": {
            "description": "Where `models` and the limits in this answer come from. `present`: the gateway's live values (a GET of one key); `missing`: the gateway no longer has the key (the registry values are shown); `not_read`: the gateway was not read and the registry values are shown. A list answers `not_read`, and so does EVERY write (create, PATCH, rotation): after a write, `live` is `not_read` and `spend_usd` is null until the next GET of the key. Read the key again (GET) for its live values.",
            "enum": [
              "present",
              "missing",
              "not_read"
            ],
            "title": "Live",
            "type": "string"
          },
          "models": {
            "description": "Tier names the key may call. A SET of tier names from the serving-tier catalogue: order carries no meaning and a name given twice counts once. Written de-duplicated and sorted (to the registry and to the gateway) and always returned sorted, so the same set always reads back the same.",
            "items": {
              "type": "string"
            },
            "title": "Models",
            "type": "array"
          },
          "organization_id": {
            "description": "The tenant (organisation) that owns the key. Frozen.",
            "title": "Organization Id",
            "type": "string"
          },
          "origin": {
            "description": "`api`: created here; `adopted`: an existing gateway key taken under management. An adopted key's value lives with its consumer, so it cannot be rotated here (409 `key_adopted`).",
            "enum": [
              "api",
              "adopted"
            ],
            "title": "Origin",
            "type": "string"
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A project of the tenant the key serves; null when it serves none in particular.",
            "title": "Project Id"
          },
          "rotated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the key's value was last replaced (a rotation); null when never.",
            "title": "Rotated At"
          },
          "rpm_limit": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Requests per minute the gateway allows the key; null for no limit.",
            "title": "Rpm Limit"
          },
          "secret": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The key's value (`sk-…`). Present ONLY in the response to the create or rotation that produced it, and only when that request set `expose_secret: true`; null everywhere else, including an idempotent replay of that same request. The value is always stored in the platform's secrets store at `secret_path`; the API never returns it again.",
            "title": "Secret"
          },
          "secret_field": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The field of that secrets-store entry that holds the value. Null when `secret_path` is.",
            "title": "Secret Field"
          },
          "secret_path": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the value is stored: a path in the platform's secrets store. Null for an adopted key whose location was never recorded.",
            "title": "Secret Path"
          },
          "soft_budget_usd": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "SOFT budget in US dollars: the gateway alerts when it is reached and NEVER blocks. There is no hard limit in v1.",
            "title": "Soft Budget Usd"
          },
          "spend_usd": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Spend the gateway has recorded for this key (shadow USD). Only in the answer to a GET of one key: null in a list, and null in the answer to every write (create, PATCH, rotation) until the next GET.",
            "title": "Spend Usd"
          },
          "token_hash_prefix": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The first 12 characters of the AI gateway's SHA-256 of the key, to find it in the AI gateway's own records. Never the value.",
            "title": "Token Hash Prefix"
          },
          "tpm_limit": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tokens per minute the gateway allows the key; null for no limit.",
            "title": "Tpm Limit"
          },
          "updated_at": {
            "description": "The last change; equal to `created_at` until the first change.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          }
        },
        "required": [
          "id",
          "organization_id",
          "env",
          "app",
          "key_alias",
          "models",
          "live",
          "origin",
          "created_at",
          "updated_at"
        ],
        "title": "GatewayKey",
        "type": "object"
      },
      "GatewayKeyCreate": {
        "additionalProperties": false,
        "description": "A new virtual key, made on the gateway and stored in the secrets store.\nIts alias is `<organisation-slug>-<env>-<app>[-<feature>]`.",
        "properties": {
          "app": {
            "description": "The application the key is for: lowercase words joined by single hyphens, 1-40 characters. Part of `key_alias`. Frozen.",
            "maxLength": 40,
            "minLength": 1,
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
            "title": "App",
            "type": "string"
          },
          "budget_duration": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,3}(s|m|h|d|mo)$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The soft budget's period: a number and `s`, `m`, `h`, `d` or `mo`, e.g. `30d`; the spend counted against `soft_budget_usd` restarts after each period.",
            "title": "Budget Duration"
          },
          "env": {
            "description": "The environment the key is for: `dev`, `uat` or `prod`. Frozen.",
            "enum": [
              "dev",
              "uat",
              "prod"
            ],
            "title": "Env",
            "type": "string"
          },
          "expose_secret": {
            "default": false,
            "description": "Return the key's value in THIS response (`secret`). It is stored in the secrets store either way and never returned again.",
            "title": "Expose Secret",
            "type": "boolean"
          },
          "feature": {
            "anyOf": [
              {
                "maxLength": 40,
                "minLength": 1,
                "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional: the application's feature the key is for, same rule as `app`. Part of `key_alias`. Frozen.",
            "title": "Feature"
          },
          "models": {
            "description": "A SET of tier names from the serving-tier catalogue: order carries no meaning and a name given twice counts once. Written de-duplicated and sorted (to the registry and to the gateway) and always returned sorted, so the same set always reads back the same. A tier that exists but serves nothing right now is accepted with a `tier_not_serving` warning.",
            "items": {
              "type": "string"
            },
            "maxItems": 50,
            "minItems": 1,
            "title": "Models",
            "type": "array"
          },
          "organization_id": {
            "description": "The owning tenant.",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
            "title": "Organization Id",
            "type": "string"
          },
          "project_id": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,8}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional: a project of that tenant the key serves.",
            "title": "Project Id"
          },
          "rpm_limit": {
            "anyOf": [
              {
                "maximum": 1000000000.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Requests per minute the gateway allows the key; null for no limit.",
            "title": "Rpm Limit"
          },
          "soft_budget_usd": {
            "anyOf": [
              {
                "exclusiveMinimum": 0.0,
                "format": "double",
                "maximum": 1000000000.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "SOFT budget in US dollars: the gateway alerts when it is reached and NEVER blocks. There is no hard limit in v1.",
            "title": "Soft Budget Usd"
          },
          "tpm_limit": {
            "anyOf": [
              {
                "maximum": 2000000000.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tokens per minute the gateway allows the key; null for no limit.",
            "title": "Tpm Limit"
          }
        },
        "required": [
          "organization_id",
          "env",
          "app",
          "models"
        ],
        "title": "GatewayKeyCreate",
        "type": "object"
      },
      "GatewayKeyPage": {
        "description": "One page of AI gateway virtual keys. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/GatewayKey"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "GatewayKeyPage",
        "type": "object"
      },
      "GatewayKeyPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. Here `null` clears a limit, the soft\nbudget, its duration or the project; `models` cannot be null. The key's value is\nnever changed here (that is a rotation).",
        "properties": {
          "app": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "App"
          },
          "budget_duration": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,3}(s|m|h|d|mo)$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Budget Duration"
          },
          "env": {
            "anyOf": [
              {
                "enum": [
                  "dev",
                  "uat",
                  "prod"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Env"
          },
          "feature": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Feature"
          },
          "models": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "maxItems": 50,
                "minItems": 1,
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "A SET of tier names from the serving-tier catalogue: order carries no meaning and a name given twice counts once. Written de-duplicated and sorted (to the registry and to the gateway) and always returned sorted, so the same set always reads back the same.",
            "title": "Models"
          },
          "organization_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Organization Id"
          },
          "project_id": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,8}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Project Id"
          },
          "rpm_limit": {
            "anyOf": [
              {
                "maximum": 1000000000.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Rpm Limit"
          },
          "soft_budget_usd": {
            "anyOf": [
              {
                "exclusiveMinimum": 0.0,
                "format": "double",
                "maximum": 1000000000.0,
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "SOFT budget in US dollars: the gateway alerts when it is reached and NEVER blocks. There is no hard limit in v1. null clears it.",
            "title": "Soft Budget Usd"
          },
          "tpm_limit": {
            "anyOf": [
              {
                "maximum": 2000000000.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Tpm Limit"
          }
        },
        "title": "GatewayKeyPatch",
        "type": "object"
      },
      "GatewayKeyRotation": {
        "additionalProperties": false,
        "description": "A rotation: the key gets a new value, the old one stops working, and\neverything else about the key stays. The body may be empty.",
        "properties": {
          "expose_secret": {
            "default": false,
            "description": "Return the NEW value in this response (`secret`). It is stored in the secrets store either way.",
            "title": "Expose Secret",
            "type": "boolean"
          }
        },
        "title": "GatewayKeyRotation",
        "type": "object"
      },
      "GitLabGroupStatus": {
        "description": "The customer's top-level GitLab group as GitLab reports it right now.",
        "properties": {
          "exists": {
            "description": "The group exists in GitLab.",
            "title": "Exists",
            "type": "boolean"
          },
          "full_path": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The group's full path; null when it does not exist.",
            "title": "Full Path"
          },
          "web_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The group's page in GitLab; null when it does not exist.",
            "title": "Web Url"
          }
        },
        "required": [
          "exists"
        ],
        "title": "GitLabGroupStatus",
        "type": "object"
      },
      "GitLabRepository": {
        "description": "A repository of the project, in the customer's GitLab group.",
        "properties": {
          "kind": {
            "description": "`app` or `www`. Other values may appear.",
            "title": "Kind",
            "type": "string"
          },
          "path": {
            "description": "`<customer group>/<repository>`.",
            "title": "Path",
            "type": "string"
          },
          "primary": {
            "description": "The project's main repository.",
            "title": "Primary",
            "type": "boolean"
          }
        },
        "required": [
          "path",
          "kind",
          "primary"
        ],
        "title": "GitLabRepository",
        "type": "object"
      },
      "KubernetesNamespace": {
        "description": "A Kubernetes namespace of the project, one per environment (Kubernetes\nbackend only).",
        "properties": {
          "env": {
            "description": "The environment, e.g. `dev`.",
            "title": "Env",
            "type": "string"
          },
          "namespace": {
            "description": "The namespace's name.",
            "title": "Namespace",
            "type": "string"
          }
        },
        "required": [
          "env",
          "namespace"
        ],
        "title": "KubernetesNamespace",
        "type": "object"
      },
      "LaunchCatalogEntry": {
        "description": "A launchable model on a node. Never the load or unload commands.",
        "properties": {
          "enabled": {
            "description": "The entry is offered for loading in the portal.",
            "title": "Enabled",
            "type": "boolean"
          },
          "engine": {
            "description": "The serving engine: `vllm`, `ollama` or `spark-vllm` (a DGX cluster). Other values may appear.",
            "title": "Engine",
            "type": "string"
          },
          "host": {
            "description": "The node (for a cluster: its head).",
            "title": "Host",
            "type": "string"
          },
          "key": {
            "description": "The entry's stable key, unique.",
            "title": "Key",
            "type": "string"
          },
          "label": {
            "description": "The name the portal shows for the entry.",
            "title": "Label",
            "type": "string"
          },
          "model": {
            "description": "The model it loads, as the serving engine names it.",
            "title": "Model",
            "type": "string"
          },
          "port": {
            "description": "The port the loaded model answers on.",
            "title": "Port",
            "type": "integer"
          }
        },
        "required": [
          "key",
          "host",
          "label",
          "model",
          "engine",
          "port",
          "enabled"
        ],
        "title": "LaunchCatalogEntry",
        "type": "object"
      },
      "LaunchCatalogPage": {
        "description": "One page of launch catalogue entries. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/LaunchCatalogEntry"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "LaunchCatalogPage",
        "type": "object"
      },
      "Licence": {
        "description": "This platform's licence: its state as the licence gate sees it, and what\nthe installed licence document says.",
        "properties": {
          "bound_fqdn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name the installed licence is bound to. A licence bound to another name puts the portal in DOMAIN_MISMATCH.",
            "title": "Bound Fqdn"
          },
          "bundle": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "SENSITIVE. The installed bundle as an `acplic1.` string, for a principal holding `licence-admin-global`; null for everyone else and when none is installed.",
            "title": "Bundle"
          },
          "days_remaining": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whole days until `valid_until`; negative in grace. Null without a term.",
            "title": "Days Remaining"
          },
          "document_digest": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256 (hex) of the installed licence document envelope — the `document` member of the bundle, as ASCII. The same value the issuer records for the document it signed. Null when none is installed.",
            "title": "Document Digest"
          },
          "fqdn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name this portal answers on, as the licence engine derives it.",
            "title": "Fqdn"
          },
          "grace_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Days of grace after `valid_until` before the licence locks (14 unless the document says otherwise); null when none is installed.",
            "title": "Grace Days"
          },
          "growth_allowed": {
            "description": "The licence gate lets the estate grow (projects, AI, customers and tenants): false in the restricted and read-only states.",
            "title": "Growth Allowed",
            "type": "boolean"
          },
          "installed_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the installed document was installed.",
            "title": "Installed At"
          },
          "instance_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "This portal's instance id, which a licence document binds. Null until the portal first activates or imports a licence.",
            "title": "Instance Id"
          },
          "licence_class": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The kind of licence: `evaluation`, `commercial`, `internal-sp` or `partner`; null when none is installed. Other values may appear.",
            "title": "Licence Class"
          },
          "licence_epoch": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The installed document's epoch; a bundle installs only when its epoch is higher (see `PUT /licence/bundle`).",
            "title": "Licence Epoch"
          },
          "licence_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The installed licence's id, as ATAILA issued it; null when none is installed. The audit row of an install names it.",
            "title": "Licence Id"
          },
          "modules": {
            "description": "Entitled modules; empty unless the state gives full function.",
            "items": {
              "type": "string"
            },
            "title": "Modules",
            "type": "array"
          },
          "overlays": {
            "description": "Conditions shown next to the state, never a state of their own: `clock_skew`, `over_deployed`.",
            "items": {
              "type": "string"
            },
            "title": "Overlays",
            "type": "array"
          },
          "product_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The product the licence is for, as ATAILA issued it, e.g. `enterprise` or `eval-internal`; null when none is installed or the document names none. Other values may appear.",
            "title": "Product Code"
          },
          "serial": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The licence serial. Shown in full only to a principal holding `licence-admin-global`; everyone else gets it masked to its last group. Null when no licence is installed.",
            "title": "Serial"
          },
          "serial_masked": {
            "description": "True when `serial` is masked for this caller.",
            "title": "Serial Masked",
            "type": "boolean"
          },
          "sockets": {
            "$ref": "#/components/schemas/LicenceSockets",
            "description": "Sockets licensed and observed."
          },
          "sp_mode_enabled": {
            "description": "The licence gate lets the service-provider plane (customers and tenants) change: requires growth, the `sp-mode` module and a tenancy mode other than `single`.",
            "title": "Sp Mode Enabled",
            "type": "boolean"
          },
          "state": {
            "description": "The licence state. `ACTIVE`, `EXPIRING` and `GRACE` give full function; `UNLICENSED`, `PENDING_ACTIVATION`, `INVALID` and `DOMAIN_MISMATCH` refuse what would grow the platform (403 `licence_restricted`); `LOCKED` and `REVOKED` refuse every change except installing a licence (403 `licence_locked`).",
            "enum": [
              "UNLICENSED",
              "PENDING_ACTIVATION",
              "INVALID",
              "DOMAIN_MISMATCH",
              "ACTIVE",
              "EXPIRING",
              "GRACE",
              "LOCKED",
              "REVOKED"
            ],
            "title": "State",
            "type": "string"
          },
          "state_reason": {
            "description": "Why the licence is in this state; empty when ACTIVE.",
            "title": "State Reason",
            "type": "string"
          },
          "tenancy_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`single` or `multi`, as the licence states it (`multi` is the service-provider plane: customers and tenants). Other values may appear.",
            "title": "Tenancy Mode"
          },
          "tier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The product tier: `standard`, `enterprise`, `enterprise-plus` or `service-provider`; null when none is installed. Other values may appear.",
            "title": "Tier"
          },
          "valid_from": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the licence term starts; null without a term.",
            "title": "Valid From"
          },
          "valid_until": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the licence term ends; null without a term. After it the licence runs in `GRACE` for `grace_days`, then `LOCKED`.",
            "title": "Valid Until"
          },
          "writes_allowed": {
            "description": "The licence gate lets ordinary changes through: false only in the read-only states (LOCKED, REVOKED).",
            "title": "Writes Allowed",
            "type": "boolean"
          }
        },
        "required": [
          "state",
          "state_reason",
          "overlays",
          "serial",
          "serial_masked",
          "licence_epoch",
          "tenancy_mode",
          "modules",
          "sockets",
          "days_remaining",
          "instance_id",
          "fqdn",
          "bound_fqdn",
          "document_digest",
          "bundle",
          "installed_at",
          "growth_allowed",
          "writes_allowed",
          "sp_mode_enabled"
        ],
        "title": "Licence",
        "type": "object"
      },
      "LicenceBundlePut": {
        "additionalProperties": false,
        "description": "A licence bundle to install in place of the installed licence document.",
        "properties": {
          "bundle": {
            "description": "SENSITIVE. The `acplic1.` bundle ATAILA issued for this portal.",
            "maxLength": 65536,
            "minLength": 1,
            "title": "Bundle",
            "type": "string"
          }
        },
        "required": [
          "bundle"
        ],
        "title": "LicenceBundlePut",
        "type": "object"
      },
      "LicenceInstalled": {
        "description": "`PUT /licence/bundle` — the licence as it is after the install.",
        "properties": {
          "bound_fqdn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name the installed licence is bound to. A licence bound to another name puts the portal in DOMAIN_MISMATCH.",
            "title": "Bound Fqdn"
          },
          "bundle": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "SENSITIVE. The installed bundle as an `acplic1.` string, for a principal holding `licence-admin-global`; null for everyone else and when none is installed.",
            "title": "Bundle"
          },
          "days_remaining": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whole days until `valid_until`; negative in grace. Null without a term.",
            "title": "Days Remaining"
          },
          "document_digest": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "sha256 (hex) of the installed licence document envelope — the `document` member of the bundle, as ASCII. The same value the issuer records for the document it signed. Null when none is installed.",
            "title": "Document Digest"
          },
          "fqdn": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name this portal answers on, as the licence engine derives it.",
            "title": "Fqdn"
          },
          "grace_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Days of grace after `valid_until` before the licence locks (14 unless the document says otherwise); null when none is installed.",
            "title": "Grace Days"
          },
          "growth_allowed": {
            "description": "The licence gate lets the estate grow (projects, AI, customers and tenants): false in the restricted and read-only states.",
            "title": "Growth Allowed",
            "type": "boolean"
          },
          "installed": {
            "const": true,
            "default": true,
            "description": "Always true: the bundle was installed (a bundle that was not is a problem, never this answer).",
            "title": "Installed",
            "type": "boolean"
          },
          "installed_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the installed document was installed.",
            "title": "Installed At"
          },
          "instance_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "This portal's instance id, which a licence document binds. Null until the portal first activates or imports a licence.",
            "title": "Instance Id"
          },
          "licence_class": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The kind of licence: `evaluation`, `commercial`, `internal-sp` or `partner`; null when none is installed. Other values may appear.",
            "title": "Licence Class"
          },
          "licence_epoch": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The installed document's epoch; a bundle installs only when its epoch is higher (see `PUT /licence/bundle`).",
            "title": "Licence Epoch"
          },
          "licence_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The installed licence's id, as ATAILA issued it; null when none is installed. The audit row of an install names it.",
            "title": "Licence Id"
          },
          "modules": {
            "description": "Entitled modules; empty unless the state gives full function.",
            "items": {
              "type": "string"
            },
            "title": "Modules",
            "type": "array"
          },
          "overlays": {
            "description": "Conditions shown next to the state, never a state of their own: `clock_skew`, `over_deployed`.",
            "items": {
              "type": "string"
            },
            "title": "Overlays",
            "type": "array"
          },
          "product_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The product the licence is for, as ATAILA issued it, e.g. `enterprise` or `eval-internal`; null when none is installed or the document names none. Other values may appear.",
            "title": "Product Code"
          },
          "serial": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The licence serial. Shown in full only to a principal holding `licence-admin-global`; everyone else gets it masked to its last group. Null when no licence is installed.",
            "title": "Serial"
          },
          "serial_masked": {
            "description": "True when `serial` is masked for this caller.",
            "title": "Serial Masked",
            "type": "boolean"
          },
          "sockets": {
            "$ref": "#/components/schemas/LicenceSockets",
            "description": "Sockets licensed and observed."
          },
          "sp_mode_enabled": {
            "description": "The licence gate lets the service-provider plane (customers and tenants) change: requires growth, the `sp-mode` module and a tenancy mode other than `single`.",
            "title": "Sp Mode Enabled",
            "type": "boolean"
          },
          "state": {
            "description": "The licence state. `ACTIVE`, `EXPIRING` and `GRACE` give full function; `UNLICENSED`, `PENDING_ACTIVATION`, `INVALID` and `DOMAIN_MISMATCH` refuse what would grow the platform (403 `licence_restricted`); `LOCKED` and `REVOKED` refuse every change except installing a licence (403 `licence_locked`).",
            "enum": [
              "UNLICENSED",
              "PENDING_ACTIVATION",
              "INVALID",
              "DOMAIN_MISMATCH",
              "ACTIVE",
              "EXPIRING",
              "GRACE",
              "LOCKED",
              "REVOKED"
            ],
            "title": "State",
            "type": "string"
          },
          "state_reason": {
            "description": "Why the licence is in this state; empty when ACTIVE.",
            "title": "State Reason",
            "type": "string"
          },
          "tenancy_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`single` or `multi`, as the licence states it (`multi` is the service-provider plane: customers and tenants). Other values may appear.",
            "title": "Tenancy Mode"
          },
          "tier": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The product tier: `standard`, `enterprise`, `enterprise-plus` or `service-provider`; null when none is installed. Other values may appear.",
            "title": "Tier"
          },
          "valid_from": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the licence term starts; null without a term.",
            "title": "Valid From"
          },
          "valid_until": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the licence term ends; null without a term. After it the licence runs in `GRACE` for `grace_days`, then `LOCKED`.",
            "title": "Valid Until"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          },
          "writes_allowed": {
            "description": "The licence gate lets ordinary changes through: false only in the read-only states (LOCKED, REVOKED).",
            "title": "Writes Allowed",
            "type": "boolean"
          }
        },
        "required": [
          "state",
          "state_reason",
          "overlays",
          "serial",
          "serial_masked",
          "licence_epoch",
          "tenancy_mode",
          "modules",
          "sockets",
          "days_remaining",
          "instance_id",
          "fqdn",
          "bound_fqdn",
          "document_digest",
          "bundle",
          "installed_at",
          "growth_allowed",
          "writes_allowed",
          "sp_mode_enabled"
        ],
        "title": "LicenceInstalled",
        "type": "object"
      },
      "LicenceSockets": {
        "description": "CPU sockets: what the licence allows and what the census measured.\n`over_deployed` in `overlays` says the estate runs more than the licence\nallows.",
        "properties": {
          "licensed": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sockets the licence allows; null when uncapped or when no licence is installed.",
            "title": "Licensed"
          },
          "observed": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sockets the latest census measured; null when no census has run.",
            "title": "Observed"
          },
          "uncapped": {
            "description": "The licence sets no socket limit.",
            "title": "Uncapped",
            "type": "boolean"
          }
        },
        "required": [
          "licensed",
          "uncapped",
          "observed"
        ],
        "title": "LicenceSockets",
        "type": "object"
      },
      "LicenceSummary": {
        "description": "The licence in short, as `GET /meta` reports it; `GET /licence` has all of it.",
        "properties": {
          "days_remaining": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Whole days until the licence term ends; negative in grace. Null without a term.",
            "title": "Days Remaining"
          },
          "state": {
            "description": "The licence state. `ACTIVE`, `EXPIRING` and `GRACE` give full function; `UNLICENSED`, `PENDING_ACTIVATION`, `INVALID` and `DOMAIN_MISMATCH` refuse what would grow the platform (403 `licence_restricted`); `LOCKED` and `REVOKED` refuse every change except installing a licence (403 `licence_locked`). Other values may appear.",
            "title": "State",
            "type": "string"
          },
          "state_reason": {
            "default": "",
            "description": "Why the licence is in this state, for a person; empty when `ACTIVE`.",
            "title": "State Reason",
            "type": "string"
          }
        },
        "required": [
          "state"
        ],
        "title": "LicenceSummary",
        "type": "object"
      },
      "LoadTarget": {
        "description": "Somewhere a model can be served, with its VRAM budget: an AI node or a\nDGX cluster. Live figures when monitoring answers and the node is online,\nstatic fallbacks otherwise.",
        "properties": {
          "engine": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The serving engine a load here uses: `vllm` (a node), `k8s-vllm` (a Kubernetes node) or `spark-vllm` (a DGX cluster). Other values may appear.",
            "title": "Engine"
          },
          "gpu_count": {
            "description": "GPUs: counted live when the node is online, estimated from its static budget otherwise; a cluster counts one per member.",
            "title": "Gpu Count",
            "type": "integer"
          },
          "hostname": {
            "description": "A node, or a DGX cluster by name.",
            "title": "Hostname",
            "type": "string"
          },
          "is_cluster": {
            "default": false,
            "description": "The target is a DGX cluster.",
            "title": "Is Cluster",
            "type": "boolean"
          },
          "loadable": {
            "description": "False for fit-only targets (DGX clusters, Kubernetes nodes).",
            "title": "Loadable",
            "type": "boolean"
          },
          "loaded_models": {
            "description": "The served names of the models loaded here right now; empty when none is, or when monitoring cannot be read.",
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ]
            },
            "title": "Loaded Models",
            "type": "array"
          },
          "members": {
            "anyOf": [
              {
                "items": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "A cluster's member hostnames, head first; null for a node.",
            "title": "Members"
          },
          "online": {
            "description": "The node (for a cluster: its head) is up, as monitoring sees it; false also when monitoring cannot be read.",
            "title": "Online",
            "type": "boolean"
          },
          "per_gpu_gb": {
            "description": "VRAM per GPU in GB.",
            "title": "Per Gpu Gb",
            "type": "integer"
          },
          "status": {
            "description": "As the AI node list reports it (`serving`, `loaded_idle`, `idle`, `offline`, `standby`, `powered_off`); for a DGX cluster `active` or `forming` while it is one. Other values may appear.",
            "title": "Status",
            "type": "string"
          },
          "tensor_parallel": {
            "description": "How many GPUs one model is spread across when served here.",
            "title": "Tensor Parallel",
            "type": "integer"
          },
          "usable_vram_gb": {
            "description": "The weight budget in GB: the share of the serving GPUs' VRAM a model's weights may take, the rest being left for its working memory. A model fits when its `size_gb` is at most this.",
            "format": "double",
            "title": "Usable Vram Gb",
            "type": "number"
          },
          "vram_total_gb": {
            "description": "`gpu_count` times `per_gpu_gb`, in GB.",
            "title": "Vram Total Gb",
            "type": "integer"
          }
        },
        "required": [
          "hostname",
          "online",
          "status",
          "gpu_count",
          "tensor_parallel",
          "per_gpu_gb",
          "vram_total_gb",
          "usable_vram_gb",
          "loaded_models",
          "loadable"
        ],
        "title": "LoadTarget",
        "type": "object"
      },
      "LoadTargetPage": {
        "description": "One page of load targets. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/LoadTarget"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "LoadTargetPage",
        "type": "object"
      },
      "Membership": {
        "description": "A person's membership of a tenant, and their role in it.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the membership was created; null on a legacy row.",
            "title": "Created At"
          },
          "role": {
            "description": "`developer` can be read (legacy rows hold it) but not written: `PUT` accepts only `owner`, `admin`, `member` and `viewer`.",
            "enum": [
              "owner",
              "admin",
              "developer",
              "member",
              "viewer"
            ],
            "title": "Role",
            "type": "string"
          },
          "tenant_id": {
            "description": "The tenant.",
            "title": "Tenant Id",
            "type": "string"
          },
          "user_id": {
            "description": "The member.",
            "title": "User Id",
            "type": "string"
          }
        },
        "required": [
          "tenant_id",
          "user_id",
          "role"
        ],
        "title": "Membership",
        "type": "object"
      },
      "MembershipPage": {
        "description": "One page of a tenant's memberships. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/Membership"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "MembershipPage",
        "type": "object"
      },
      "MembershipPut": {
        "additionalProperties": false,
        "description": "The member's role in the tenant.",
        "properties": {
          "role": {
            "description": "`owner`, `admin`, `member` or `viewer`.",
            "enum": [
              "owner",
              "admin",
              "member",
              "viewer"
            ],
            "title": "Role",
            "type": "string"
          }
        },
        "required": [
          "role"
        ],
        "title": "MembershipPut",
        "type": "object"
      },
      "Meta": {
        "description": "What this API and this platform are. Read it before the first write:\n`licence.state` says whether writes will be refused, and\n`dispatch_mode_effective` whether provisioning can complete here.",
        "properties": {
          "api_version": {
            "description": "This API's version, semantic versioning (`1.0.0`). Within `1.x` the contract only ever grows.",
            "title": "Api Version",
            "type": "string"
          },
          "dispatch_mode_effective": {
            "description": "What pipeline dispatch does on this platform, as `/api/version` reports it. `live`: work runs. `dryrun`: the dispatch is faked, nothing is executed, and provisioning or a release never completes. `simulate`: provisioning stages are marked done without running (`simulate_stage_seconds` each) and every other dispatch behaves as `dryrun`. Read it before booking work, to fail fast on a platform that will not carry it out.",
            "enum": [
              "live",
              "dryrun",
              "simulate"
            ],
            "title": "Dispatch Mode Effective",
            "type": "string"
          },
          "licence": {
            "$ref": "#/components/schemas/LicenceSummary",
            "description": "The licence state in short."
          },
          "modules": {
            "default": [],
            "description": "The modules the licence entitles; empty unless the licence state gives full function.",
            "items": {
              "type": "string"
            },
            "title": "Modules",
            "type": "array"
          },
          "platform_version": {
            "description": "The platform build that answers, e.g. `1.0.181`. Release notes and the developer documentation name contract changes by this version.",
            "title": "Platform Version",
            "type": "string"
          },
          "simulate_stage_seconds": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Under `simulate`: how long a simulated provisioning stage takes. Null in every other mode.",
            "title": "Simulate Stage Seconds"
          },
          "tenancy_mode": {
            "default": "",
            "description": "`single` or `multi`, as the licence states it (`multi` is the service-provider plane: customers and tenants); empty without a licence.",
            "title": "Tenancy Mode",
            "type": "string"
          },
          "tier": {
            "default": "",
            "description": "The licence's product tier; empty without a licence.",
            "title": "Tier",
            "type": "string"
          }
        },
        "required": [
          "api_version",
          "platform_version",
          "licence",
          "dispatch_mode_effective",
          "simulate_stage_seconds"
        ],
        "title": "Meta",
        "type": "object"
      },
      "NodeCache": {
        "description": "A copy of a model's weights on one AI node's local disk: the fast,\noffline-ready serving copy, made from the central store by a cache run.",
        "properties": {
          "id": {
            "description": "`<model id>:<node>`.",
            "title": "Id",
            "type": "string"
          },
          "model_id": {
            "description": "The model (`id` of an AI model).",
            "title": "Model Id",
            "type": "string"
          },
          "node": {
            "description": "The AI node's hostname.",
            "title": "Node",
            "type": "string"
          },
          "path": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the copy is on the node's disk, as the cache run reported it.",
            "title": "Path"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The copy's size on the node's disk in GB, when measured.",
            "title": "Size Gb"
          },
          "state": {
            "description": "`cached` once the copy is complete; `pulling` while it is made; `absent` or `failed` when a copy was removed or did not finish. Other values may appear.",
            "title": "State",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the copy was last made or checked.",
            "title": "Updated At"
          }
        },
        "required": [
          "id",
          "model_id",
          "node",
          "state"
        ],
        "title": "NodeCache",
        "type": "object"
      },
      "NodeCachePage": {
        "description": "One page of a model's node caches. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/NodeCache"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "NodeCachePage",
        "type": "object"
      },
      "NodeCacheRef": {
        "description": "A node that holds, or held, a copy of the model: the short form of a node\ncache (`GET /ai-models/{id}/node-caches/{node}` has the rest).",
        "properties": {
          "node": {
            "description": "The AI node's hostname.",
            "title": "Node",
            "type": "string"
          },
          "size_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "The copy's size on the node's disk in GB, when measured.",
            "title": "Size Gb"
          },
          "state": {
            "description": "`cached` once the copy is complete; `pulling` while it is made; `absent` or `failed` when a copy was removed or did not finish. Other values may appear.",
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "node",
          "state"
        ],
        "title": "NodeCacheRef",
        "type": "object"
      },
      "NodeCluster": {
        "description": "The DGX cluster a node is a member of, as monitoring reports it.",
        "properties": {
          "name": {
            "description": "The cluster's name (`name` of a DGX cluster).",
            "title": "Name",
            "type": "string"
          },
          "role": {
            "description": "The node's role in it: `head` or `worker`. Other values may appear.",
            "title": "Role",
            "type": "string"
          }
        },
        "required": [
          "name",
          "role"
        ],
        "title": "NodeCluster",
        "type": "object"
      },
      "NodeModel": {
        "description": "A model loaded on a node right now, as monitoring reports it.",
        "properties": {
          "cluster": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The DGX cluster serving it, when it is served by a cluster rather than by this node alone.",
            "title": "Cluster"
          },
          "engine": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The serving engine, e.g. `vllm` or `ollama`. Other values may appear.",
            "title": "Engine"
          },
          "max_model_len": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The longest context, in tokens, it is served with, when reported.",
            "title": "Max Model Len"
          },
          "model": {
            "description": "The model as the serving engine names it (its repo or path).",
            "title": "Model",
            "type": "string"
          },
          "port": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The serving port (a node can run several).",
            "title": "Port"
          },
          "served_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The name clients call it by on the node's OpenAI-compatible endpoint; null when not reported.",
            "title": "Served Name"
          },
          "tensor_parallel": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "How many GPUs the model is spread across, when reported.",
            "title": "Tensor Parallel"
          },
          "tiers": {
            "description": "Serving tiers it backs right now.",
            "items": {
              "type": "string"
            },
            "title": "Tiers",
            "type": "array"
          }
        },
        "required": [
          "model"
        ],
        "title": "NodeModel",
        "type": "object"
      },
      "NodeStorage": {
        "description": "A node's local disk as last scanned, with the models cached on it.",
        "properties": {
          "cached": {
            "description": "The models with a complete copy on this node, largest first.",
            "items": {
              "$ref": "#/components/schemas/CachedModelRef"
            },
            "title": "Cached",
            "type": "array"
          },
          "captured_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was last scanned; null when never.",
            "title": "Captured At"
          },
          "free_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free space in GB, as last scanned.",
            "title": "Free Gb"
          },
          "kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The kind of disk, as the scan reported it: `nvme`, `hdd` or `raid`. Other values may appear.",
            "title": "Kind"
          },
          "mount": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the storage is mounted, as the scan reported it.",
            "title": "Mount"
          },
          "name": {
            "description": "The share's name, or the node's hostname.",
            "title": "Name",
            "type": "string"
          },
          "total_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total capacity in GB, as last scanned.",
            "title": "Total Gb"
          }
        },
        "required": [
          "name"
        ],
        "title": "NodeStorage",
        "type": "object"
      },
      "Operation": {
        "description": "Long-running work: answered with 202 and a `Location`, then polled at\n`GET /operations/{id}` until `status` is `succeeded` or `failed`.",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the work was booked.",
            "title": "Created At"
          },
          "dispatch_mode": {
            "anyOf": [
              {
                "enum": [
                  "live",
                  "dryrun",
                  "simulate"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "For work that dispatches pipelines: `dryrun` means this platform fakes the dispatch, nothing is executed, and the operation can never succeed; `simulate` means stages are marked done without running (see `simulated`).",
            "title": "Dispatch Mode"
          },
          "error": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "When `status` is `failed`: `code` says why (`stage_failed` with the `stage`, `release_failed`, `rejected`, `operation_timed_out`, `run_failed`, `run_timeout`, ...), and `message` (`detail` for a model store run) says it for a person. Null otherwise.",
            "title": "Error"
          },
          "id": {
            "description": "`<kind>:<native id>`, e.g. `provision:4711`. The `Location` of the 202 that started it is `/api/v1/operations/<id>`.",
            "title": "Id",
            "type": "string"
          },
          "kind": {
            "description": "What the work is: `provision` (project provisioning), `release` (a release promotion), `model-store-run` (a model node cache or uncache, or a store run started in the portal) or `order` (a tenant order, placed in the portal; this API can poll one but not create it). Other kinds may appear.",
            "title": "Kind",
            "type": "string"
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What is happening or what happened, for a person. The wording may change.",
            "title": "Message"
          },
          "partial": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "For tenant orders (`order:<id>`, placed in the portal: this API can poll an order but not create one): `true` when the order `succeeded` only in part — what was delivered does not fully match what was ordered; `message` says what is missing.",
            "title": "Partial"
          },
          "pipeline_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "For release operations: the pipeline carrying the work out, once one is known.",
            "title": "Pipeline Url"
          },
          "resource_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "That thing's id (`<model id>:<node>` for a node cache).",
            "title": "Resource Id"
          },
          "resource_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the work is about: `project`, `release_operation`, `ai_model`, `ai_model_node_cache`, `ai_node` or `order`. Other values may appear.",
            "title": "Resource Type"
          },
          "simulated": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "For project provisioning: the result rests on SIMULATED stages (`dispatch_mode` `simulate`). A succeeded simulated operation provisioned nothing.",
            "title": "Simulated"
          },
          "stage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "For work done in stages (project provisioning): the stage it is on, or the one it stopped at.",
            "title": "Stage"
          },
          "status": {
            "description": "`pending`, `running`, `awaiting_approval` (a person must approve it in the portal), `awaiting_operator` (a person must act in the portal), `succeeded` or `failed`. The last two are final.",
            "enum": [
              "pending",
              "running",
              "awaiting_approval",
              "awaiting_operator",
              "succeeded",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it last changed; the end, once it has ended.",
            "title": "Updated At"
          }
        },
        "required": [
          "id",
          "kind",
          "status"
        ],
        "title": "Operation",
        "type": "object"
      },
      "Orchestration": {
        "description": "The orchestration walking the project's stages right now: one at a time,\nin dependency order. It is the operation `provision:<id>`.",
        "properties": {
          "current_stage": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The stage it is on (a stage `key`); null between stages.",
            "title": "Current Stage"
          },
          "kind": {
            "description": "`apply-all`: every stage not yet done; `apply-pending`: only the stale stages; `delete-all`: a teardown, started in the portal.",
            "enum": [
              "apply-all",
              "apply-pending",
              "delete-all"
            ],
            "title": "Kind",
            "type": "string"
          },
          "operation_id": {
            "description": "`provision:<id>`: poll it at /operations/{id}.",
            "title": "Operation Id",
            "type": "string"
          },
          "stale": {
            "description": "Its worker stopped heartbeating; it is resumed by the platform, not by a new start.",
            "title": "Stale",
            "type": "boolean"
          },
          "started_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it started.",
            "title": "Started At"
          },
          "status": {
            "description": "The operation's status, as `GET /operations/{id}` reports it.",
            "enum": [
              "pending",
              "running",
              "awaiting_approval",
              "awaiting_operator",
              "succeeded",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          },
          "updated_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Its last heartbeat or step.",
            "title": "Updated At"
          }
        },
        "required": [
          "operation_id",
          "kind",
          "status",
          "stale"
        ],
        "title": "Orchestration",
        "type": "object"
      },
      "Permission": {
        "description": "A fine-grained permission key the portal honours: one level of one\nfeature, in one scope.",
        "properties": {
          "category": {
            "description": "The group the portal lists the key under, e.g. `AI` or `Security`.",
            "title": "Category",
            "type": "string"
          },
          "description": {
            "description": "What holding the key allows, for a person.",
            "title": "Description",
            "type": "string"
          },
          "feature": {
            "description": "The feature the key is about, e.g. `users`.",
            "title": "Feature",
            "type": "string"
          },
          "grantable": {
            "description": "May be granted to a person (`PUT /users/{id}/roles/{key}`). A key that is not grantable is still honoured for those who hold it.",
            "title": "Grantable",
            "type": "boolean"
          },
          "key": {
            "description": "`<feature>-<level>-<scope>`, e.g. `users-read-global`: what a role grant, a token's scopes and a 403's `required` name.",
            "title": "Key",
            "type": "string"
          },
          "label": {
            "description": "The key's name, for a person.",
            "title": "Label",
            "type": "string"
          },
          "level": {
            "description": "`read` reads; `admin` also changes. An operation that reads accepts either.",
            "enum": [
              "read",
              "admin"
            ],
            "title": "Level",
            "type": "string"
          },
          "mintable": {
            "description": "May be carried by an API token.",
            "title": "Mintable",
            "type": "boolean"
          },
          "scope": {
            "description": "`global`: the whole platform. `tenant`: limited to the holder's tenants where the feature enforces it; an API token carries `global` keys only.",
            "enum": [
              "global",
              "tenant"
            ],
            "title": "Scope",
            "type": "string"
          }
        },
        "required": [
          "key",
          "feature",
          "level",
          "scope",
          "category",
          "label",
          "description",
          "grantable",
          "mintable"
        ],
        "title": "Permission",
        "type": "object"
      },
      "PermissionPage": {
        "description": "One page of the permission catalogue. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/Permission"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "PermissionPage",
        "type": "object"
      },
      "Problem": {
        "additionalProperties": true,
        "description": "An error, as RFC 9457 problem details (`application/problem+json`). Some\ncodes add members of their own: `errors` and `field` (`validation_failed`),\n`required` (`forbidden`), `state`, `state_reason`, `remedy`, `remedy_url` and\n`entitlement` (the `licence_*` codes), `blockers` (a refused delete),\n`current_version` (`version_mismatch`) and `operation_id` (work that is\nalready running). A client should ignore a member it does not know.",
        "properties": {
          "code": {
            "description": "The stable, machine-readable reason, e.g. `customer_not_found`. Each operation names its own codes in its responses; the codes every operation can answer are listed under Errors in the API description.",
            "title": "Code",
            "type": "string"
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What went wrong this time, written for a person. The wording may change at any time: branch on `code`, never on `detail`.",
            "title": "Detail"
          },
          "instance": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The path of the request that failed.",
            "title": "Instance"
          },
          "request_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The request's id, the same as the `X-Request-ID` response header. Quote it when asking for support.",
            "title": "Request Id"
          },
          "status": {
            "description": "The HTTP status code of the response, repeated.",
            "title": "Status",
            "type": "integer"
          },
          "title": {
            "description": "The HTTP status phrase, e.g. `Forbidden`.",
            "title": "Title",
            "type": "string"
          },
          "type": {
            "description": "`urn:ataila:api:problem:<code>`: names the kind of problem, the same for every occurrence of a code. An identifier, not a link.",
            "title": "Type",
            "type": "string"
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "title": "Problem",
        "type": "object"
      },
      "ProdLock": {
        "description": "A project's PROD data lock. While it is set, no data copy may target\nPROD, so PROD stays the source of truth for its data. It does not block\ncode promotion.",
        "properties": {
          "locked": {
            "description": "The lock is set.",
            "title": "Locked",
            "type": "boolean"
          },
          "locked_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was set; null while it is not.",
            "title": "Locked At"
          },
          "locked_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who set it (an e-mail address, as recorded); null while it is not set.",
            "title": "Locked By"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          }
        },
        "required": [
          "project_id",
          "locked"
        ],
        "title": "ProdLock",
        "type": "object"
      },
      "ProdLockPut": {
        "additionalProperties": false,
        "description": "The PROD data lock's new state. Setting the state it already has changes\nnothing.",
        "properties": {
          "confirm_unlock": {
            "anyOf": [
              {
                "maxLength": 64,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required to UNLOCK: the project's short name, exactly.",
            "title": "Confirm Unlock"
          },
          "locked": {
            "description": "`true` sets the lock; `false` releases it and needs `confirm_unlock`.",
            "title": "Locked",
            "type": "boolean"
          }
        },
        "required": [
          "locked"
        ],
        "title": "ProdLockPut",
        "type": "object"
      },
      "Project": {
        "description": "A project: its settings, its identity (frozen once created) and `outputs`,\nthe names its provisioning produces.",
        "properties": {
          "allow_public_https_egress": {
            "default": false,
            "description": "Kubernetes projects: allow egress to public HTTPS.",
            "title": "Allow Public Https Egress",
            "type": "boolean"
          },
          "api_exposure": {
            "default": "INTERNAL_ONLY",
            "description": "Who reaches the PROD API: `INTERNAL_ONLY` (default) or `PUBLIC`. The UAT and DEV APIs are never public.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Api Exposure",
            "type": "string"
          },
          "app_gateway": {
            "default": "shared",
            "description": "`shared` rides the environment's app gateway; `dedicated` gets its own.",
            "enum": [
              "shared",
              "dedicated"
            ],
            "title": "App Gateway",
            "type": "string"
          },
          "created_at": {
            "description": "When the project was registered.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The tenant's customer; null only for a tenant no customer owns.",
            "title": "Customer Id"
          },
          "deployment_backend": {
            "description": "`k8s` (default): namespaces on the shared Kubernetes clusters; `vm`: virtual machines of its own. Frozen.",
            "enum": [
              "vm",
              "k8s"
            ],
            "title": "Deployment Backend",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters.",
            "title": "Description"
          },
          "enable_ai": {
            "default": false,
            "description": "An AI endpoint at `ai.<primary_domain>`. Also allows outbound HTTPS to the internet, as `allow_public_https_egress` does.",
            "title": "Enable Ai",
            "type": "boolean"
          },
          "enable_cache": {
            "default": false,
            "description": "An in-memory key-value cache.",
            "title": "Enable Cache",
            "type": "boolean"
          },
          "enable_dr_db_replica": {
            "default": true,
            "description": "A disaster-recovery replica of the PROD database.",
            "title": "Enable Dr Db Replica",
            "type": "boolean"
          },
          "enable_dr_object_storage_mirror": {
            "default": true,
            "description": "A disaster-recovery mirror of the PROD object storage.",
            "title": "Enable Dr Object Storage Mirror",
            "type": "boolean"
          },
          "enable_fullstack_app": {
            "default": true,
            "description": "An application: its front end at `app.<primary_domain>` and its API at `api.<primary_domain>`, in PROD, UAT and DEV.",
            "title": "Enable Fullstack App",
            "type": "boolean"
          },
          "enable_iis": {
            "default": false,
            "description": "IIS/.NET hosting. VM backend only.",
            "title": "Enable Iis",
            "type": "boolean"
          },
          "enable_mssql": {
            "default": false,
            "description": "SQL Server. VM backend only.",
            "title": "Enable Mssql",
            "type": "boolean"
          },
          "enable_nas_object_storage_replication": {
            "default": false,
            "description": "Replication of the object storage to the central store: recorded, not acted on yet.",
            "title": "Enable Nas Object Storage Replication",
            "type": "boolean"
          },
          "enable_object_storage": {
            "default": true,
            "description": "Object storage for the project; false provisions none (a database-only project).",
            "title": "Enable Object Storage",
            "type": "boolean"
          },
          "enable_static_site": {
            "default": true,
            "description": "A web site at `www.<primary_domain>` (and `uat.www.`, `dev.www.`), seeded from `www_template`.",
            "title": "Enable Static Site",
            "type": "boolean"
          },
          "enable_uat_app_public": {
            "default": false,
            "description": "Make the UAT front end (`uat.app.`) reachable from the internet, e.g. to share a preview. DEV is never public.",
            "title": "Enable Uat App Public",
            "type": "boolean"
          },
          "enable_uat_www_public": {
            "default": false,
            "description": "Make the UAT web site (`uat.www.`) reachable from the internet.",
            "title": "Enable Uat Www Public",
            "type": "boolean"
          },
          "enable_web_www": {
            "default": true,
            "description": "The web site ships from its own `<gitlab_repo_slug>-www` repository. Provisioning does not read it: the web site, its repository and its stages follow `enable_static_site` alone. With `false`, the platform's security scans leave the web site out, and a project with no application drops out of the traffic views. Keep it `true` (the default) unless the web site is not built from that repository.",
            "title": "Enable Web Www",
            "type": "boolean"
          },
          "frontend_exposure": {
            "default": "PUBLIC",
            "description": "Who reaches the PROD front end: `PUBLIC` (the internet; default) or `INTERNAL_ONLY`.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Frontend Exposure",
            "type": "string"
          },
          "frontend_variant": {
            "default": "react",
            "description": "The front-end framework the application is generated with: `react` (default), `angular`, `vue` or `nuxt4`.",
            "enum": [
              "react",
              "angular",
              "vue",
              "nuxt4"
            ],
            "title": "Frontend Variant",
            "type": "string"
          },
          "github_repo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub repository URL, recorded in the project's manifest as its mirror.",
            "title": "Github Repo Url"
          },
          "github_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub user name, recorded with the project.",
            "title": "Github User"
          },
          "gitlab_repo_slug": {
            "description": "The repository name in the customer's GitLab group. Frozen.",
            "title": "Gitlab Repo Slug",
            "type": "string"
          },
          "has_mobile": {
            "default": false,
            "description": "The project has a mobile app. Its PROD API is then public whatever `api_exposure` says: the app calls it from the internet.",
            "title": "Has Mobile",
            "type": "boolean"
          },
          "id": {
            "description": "The project's id.",
            "title": "Id",
            "type": "string"
          },
          "import_existing_repo": {
            "default": false,
            "description": "The GitLab repository already holds code: provisioning does not seed it from the template.",
            "title": "Import Existing Repo",
            "type": "boolean"
          },
          "is_self": {
            "description": "One of ATAILA's own platform projects: readable, never writable through v1.",
            "title": "Is Self",
            "type": "boolean"
          },
          "long_name": {
            "description": "The project's display name, 2-60 characters. Double quotes, apostrophes, backslashes and control characters are refused: the name is written into the project's generated files.",
            "maxLength": 60,
            "minLength": 2,
            "title": "Long Name",
            "type": "string"
          },
          "mssql_edition": {
            "default": "express",
            "description": "The SQL Server edition PROD and UAT run, with `enable_mssql`: `express` (default; free), `standard` or `enterprise` (licensed through the platform operator).",
            "enum": [
              "express",
              "standard",
              "enterprise"
            ],
            "title": "Mssql Edition",
            "type": "string"
          },
          "network_only": {
            "description": "Only the network zone is registered: no application and no web site. Frozen.",
            "title": "Network Only",
            "type": "boolean"
          },
          "outputs": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProjectOutputs"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the project's compiled manifest names; null for a project registered without one."
          },
          "primary_domain": {
            "description": "The domain the project's sites are named under (`www.`, `app.`, `api.`, `ai.`). Frozen.",
            "title": "Primary Domain",
            "type": "string"
          },
          "prod_object_storage_disks_per_vm": {
            "default": 2,
            "description": "Data disks per PROD object storage node.",
            "enum": [
              1,
              2
            ],
            "title": "Prod Object Storage Disks Per Vm",
            "type": "integer"
          },
          "prod_object_storage_node_count": {
            "default": 2,
            "description": "PROD object storage nodes. With `enable_object_storage`, nodes times `prod_object_storage_disks_per_vm` must be at least 4.",
            "enum": [
              2,
              4
            ],
            "title": "Prod Object Storage Node Count",
            "type": "integer"
          },
          "project_index": {
            "description": "The third octet of the project's networks; unique on the platform. Frozen.",
            "title": "Project Index",
            "type": "integer"
          },
          "registered_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the user (a person or a service account) who registered the project; null when that was not recorded.",
            "title": "Registered By"
          },
          "short_name": {
            "description": "Lowercase letters and digits, unique on the platform. Frozen.",
            "title": "Short Name",
            "type": "string"
          },
          "status": {
            "description": "Read-only. `planned` until provisioning starts, `active` once every stage is done; also `provisioning`, `paused` and `retired`.",
            "enum": [
              "planned",
              "provisioning",
              "active",
              "paused",
              "retired"
            ],
            "title": "Status",
            "type": "string"
          },
          "tenant_id": {
            "description": "The owning tenant. Frozen.",
            "title": "Tenant Id",
            "type": "string"
          },
          "warnings": {
            "default": [],
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          },
          "windows_vm_count_dev": {
            "default": 0,
            "description": "Windows Server VMs in DEV, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Dev",
            "type": "integer"
          },
          "windows_vm_count_prod": {
            "default": 0,
            "description": "Windows Server VMs in PROD, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Prod",
            "type": "integer"
          },
          "windows_vm_count_uat": {
            "default": 0,
            "description": "Windows Server VMs in UAT, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Uat",
            "type": "integer"
          },
          "www_template": {
            "default": "template-www",
            "description": "What seeds the web site's repository: `template-www` (an information site; default) or `template-blog` (articles in Markdown, with feeds). Ignored without `enable_static_site`.",
            "enum": [
              "template-www",
              "template-blog"
            ],
            "title": "Www Template",
            "type": "string"
          }
        },
        "required": [
          "long_name",
          "id",
          "tenant_id",
          "customer_id",
          "project_index",
          "short_name",
          "gitlab_repo_slug",
          "primary_domain",
          "deployment_backend",
          "network_only",
          "status",
          "is_self",
          "registered_by",
          "created_at"
        ],
        "title": "Project",
        "type": "object"
      },
      "ProjectCreate": {
        "additionalProperties": false,
        "description": "A new project: registered and its manifest compiled. Provisions nothing:\n`POST /projects/{id}/provisioning` does.",
        "properties": {
          "allow_public_https_egress": {
            "default": false,
            "description": "Kubernetes projects: allow egress to public HTTPS.",
            "title": "Allow Public Https Egress",
            "type": "boolean"
          },
          "api_exposure": {
            "default": "INTERNAL_ONLY",
            "description": "Who reaches the PROD API: `INTERNAL_ONLY` (default) or `PUBLIC`. The UAT and DEV APIs are never public.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Api Exposure",
            "type": "string"
          },
          "app_gateway": {
            "default": "shared",
            "description": "`shared` rides the environment's app gateway; `dedicated` gets its own.",
            "enum": [
              "shared",
              "dedicated"
            ],
            "title": "App Gateway",
            "type": "string"
          },
          "deployment_backend": {
            "default": "k8s",
            "description": "`k8s` (default): namespaces on the shared Kubernetes clusters; `vm`: virtual machines of its own. Frozen.",
            "enum": [
              "vm",
              "k8s"
            ],
            "title": "Deployment Backend",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters.",
            "title": "Description"
          },
          "enable_ai": {
            "default": false,
            "description": "An AI endpoint at `ai.<primary_domain>`. Also allows outbound HTTPS to the internet, as `allow_public_https_egress` does.",
            "title": "Enable Ai",
            "type": "boolean"
          },
          "enable_cache": {
            "default": false,
            "description": "An in-memory key-value cache.",
            "title": "Enable Cache",
            "type": "boolean"
          },
          "enable_dr_db_replica": {
            "default": true,
            "description": "A disaster-recovery replica of the PROD database.",
            "title": "Enable Dr Db Replica",
            "type": "boolean"
          },
          "enable_dr_object_storage_mirror": {
            "default": true,
            "description": "A disaster-recovery mirror of the PROD object storage.",
            "title": "Enable Dr Object Storage Mirror",
            "type": "boolean"
          },
          "enable_fullstack_app": {
            "default": true,
            "description": "An application: its front end at `app.<primary_domain>` and its API at `api.<primary_domain>`, in PROD, UAT and DEV.",
            "title": "Enable Fullstack App",
            "type": "boolean"
          },
          "enable_iis": {
            "default": false,
            "description": "IIS/.NET hosting. VM backend only.",
            "title": "Enable Iis",
            "type": "boolean"
          },
          "enable_mssql": {
            "default": false,
            "description": "SQL Server. VM backend only.",
            "title": "Enable Mssql",
            "type": "boolean"
          },
          "enable_nas_object_storage_replication": {
            "default": false,
            "description": "Replication of the object storage to the central store: recorded, not acted on yet.",
            "title": "Enable Nas Object Storage Replication",
            "type": "boolean"
          },
          "enable_object_storage": {
            "default": true,
            "description": "Object storage for the project; false provisions none (a database-only project).",
            "title": "Enable Object Storage",
            "type": "boolean"
          },
          "enable_static_site": {
            "default": true,
            "description": "A web site at `www.<primary_domain>` (and `uat.www.`, `dev.www.`), seeded from `www_template`.",
            "title": "Enable Static Site",
            "type": "boolean"
          },
          "enable_uat_app_public": {
            "default": false,
            "description": "Make the UAT front end (`uat.app.`) reachable from the internet, e.g. to share a preview. DEV is never public.",
            "title": "Enable Uat App Public",
            "type": "boolean"
          },
          "enable_uat_www_public": {
            "default": false,
            "description": "Make the UAT web site (`uat.www.`) reachable from the internet.",
            "title": "Enable Uat Www Public",
            "type": "boolean"
          },
          "enable_web_www": {
            "default": true,
            "description": "The web site ships from its own `<gitlab_repo_slug>-www` repository. Provisioning does not read it: the web site, its repository and its stages follow `enable_static_site` alone. With `false`, the platform's security scans leave the web site out, and a project with no application drops out of the traffic views. Keep it `true` (the default) unless the web site is not built from that repository.",
            "title": "Enable Web Www",
            "type": "boolean"
          },
          "frontend_exposure": {
            "default": "PUBLIC",
            "description": "Who reaches the PROD front end: `PUBLIC` (the internet; default) or `INTERNAL_ONLY`.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Frontend Exposure",
            "type": "string"
          },
          "frontend_variant": {
            "default": "react",
            "description": "The front-end framework the application is generated with: `react` (default), `angular`, `vue` or `nuxt4`.",
            "enum": [
              "react",
              "angular",
              "vue",
              "nuxt4"
            ],
            "title": "Frontend Variant",
            "type": "string"
          },
          "github_repo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub repository URL, recorded in the project's manifest as its mirror.",
            "title": "Github Repo Url"
          },
          "github_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub user name, recorded with the project.",
            "title": "Github User"
          },
          "gitlab_repo_slug": {
            "description": "The repository name in the customer's GitLab group; unique within the customer. Frozen.",
            "pattern": "^[a-z][a-z0-9-]{1,40}$",
            "title": "Gitlab Repo Slug",
            "type": "string"
          },
          "has_mobile": {
            "default": false,
            "description": "The project has a mobile app. Its PROD API is then public whatever `api_exposure` says: the app calls it from the internet.",
            "title": "Has Mobile",
            "type": "boolean"
          },
          "import_existing_repo": {
            "default": false,
            "description": "The GitLab repository already holds code: provisioning does not seed it from the template.",
            "title": "Import Existing Repo",
            "type": "boolean"
          },
          "long_name": {
            "description": "The project's display name, 2-60 characters. Double quotes, apostrophes, backslashes and control characters are refused: the name is written into the project's generated files.",
            "maxLength": 60,
            "minLength": 2,
            "title": "Long Name",
            "type": "string"
          },
          "mssql_edition": {
            "default": "express",
            "description": "The SQL Server edition PROD and UAT run, with `enable_mssql`: `express` (default; free), `standard` or `enterprise` (licensed through the platform operator).",
            "enum": [
              "express",
              "standard",
              "enterprise"
            ],
            "title": "Mssql Edition",
            "type": "string"
          },
          "network_only": {
            "default": false,
            "description": "Register the network zone only: no app, no web site. Forces `enable_static_site` and `enable_fullstack_app` off. Frozen.",
            "title": "Network Only",
            "type": "boolean"
          },
          "primary_domain": {
            "description": "The domain the project's sites are named under (`www.`, `app.`, `api.`, `ai.`). Frozen.",
            "maxLength": 253,
            "title": "Primary Domain",
            "type": "string"
          },
          "prod_object_storage_disks_per_vm": {
            "default": 2,
            "description": "Data disks per PROD object storage node.",
            "enum": [
              1,
              2
            ],
            "title": "Prod Object Storage Disks Per Vm",
            "type": "integer"
          },
          "prod_object_storage_node_count": {
            "default": 2,
            "description": "PROD object storage nodes. With `enable_object_storage`, nodes times `prod_object_storage_disks_per_vm` must be at least 4.",
            "enum": [
              2,
              4
            ],
            "title": "Prod Object Storage Node Count",
            "type": "integer"
          },
          "project_index": {
            "anyOf": [
              {
                "maximum": 99.0,
                "minimum": 1.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The third octet of the project's networks, estate-wide unique. Omit it and the server allocates one above the highest in use (never below 4). Frozen.",
            "title": "Project Index"
          },
          "short_name": {
            "description": "Lowercase letters and digits, 2-11, starting with a letter. Estate-wide unique. Frozen.",
            "pattern": "^[a-z][a-z0-9]{1,10}$",
            "title": "Short Name",
            "type": "string"
          },
          "tenant_id": {
            "description": "The owning tenant. Frozen.",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
            "title": "Tenant Id",
            "type": "string"
          },
          "windows_vm_count_dev": {
            "default": 0,
            "description": "Windows Server VMs in DEV, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Dev",
            "type": "integer"
          },
          "windows_vm_count_prod": {
            "default": 0,
            "description": "Windows Server VMs in PROD, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Prod",
            "type": "integer"
          },
          "windows_vm_count_uat": {
            "default": 0,
            "description": "Windows Server VMs in UAT, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Uat",
            "type": "integer"
          },
          "www_template": {
            "default": "template-www",
            "description": "What seeds the web site's repository: `template-www` (an information site; default) or `template-blog` (articles in Markdown, with feeds). Ignored without `enable_static_site`.",
            "enum": [
              "template-www",
              "template-blog"
            ],
            "title": "Www Template",
            "type": "string"
          }
        },
        "required": [
          "long_name",
          "tenant_id",
          "short_name",
          "gitlab_repo_slug",
          "primary_domain"
        ],
        "title": "ProjectCreate",
        "type": "object"
      },
      "ProjectMember": {
        "description": "A person's role on one project (in addition to what their tenant\nmembership gives them).",
        "properties": {
          "created_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the role was given; null on a legacy row.",
            "title": "Created At"
          },
          "gitlab_role": {
            "anyOf": [
              {
                "enum": [
                  "guest",
                  "reporter",
                  "developer",
                  "maintainer"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "RECORDED, NOT ENFORCED: nothing creates the GitLab user or its GitLab membership from this value.",
            "title": "Gitlab Role"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          },
          "role": {
            "description": "`owner`, `admin`, `developer`, `member` or `viewer`.",
            "enum": [
              "owner",
              "admin",
              "developer",
              "member",
              "viewer"
            ],
            "title": "Role",
            "type": "string"
          },
          "user_id": {
            "description": "The member.",
            "title": "User Id",
            "type": "string"
          }
        },
        "required": [
          "project_id",
          "user_id",
          "role"
        ],
        "title": "ProjectMember",
        "type": "object"
      },
      "ProjectMemberPage": {
        "description": "One page of a project's members. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/ProjectMember"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "ProjectMemberPage",
        "type": "object"
      },
      "ProjectMemberPut": {
        "additionalProperties": false,
        "description": "The member's role on the project.",
        "properties": {
          "gitlab_role": {
            "anyOf": [
              {
                "enum": [
                  "guest",
                  "reporter",
                  "developer",
                  "maintainer"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Recorded, not enforced. `maintainer` is refused for a person who is not ATAILA staff.",
            "title": "Gitlab Role"
          },
          "role": {
            "default": "developer",
            "description": "`owner`, `admin`, `developer` (default), `member` or `viewer`.",
            "enum": [
              "owner",
              "admin",
              "developer",
              "member",
              "viewer"
            ],
            "title": "Role",
            "type": "string"
          }
        },
        "title": "ProjectMemberPut",
        "type": "object"
      },
      "ProjectOutputs": {
        "description": "What the project's compiled manifest names, curated: never an internal\naddress, a machine's host name or a production secrets store path.",
        "properties": {
          "gitlab_repositories": {
            "default": [],
            "description": "The project's repositories in GitLab.",
            "items": {
              "$ref": "#/components/schemas/GitLabRepository"
            },
            "title": "Gitlab Repositories",
            "type": "array"
          },
          "image_registry_namespace": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The project's namespace in the platform's image registry.",
            "title": "Image Registry Namespace"
          },
          "kubernetes_namespaces": {
            "default": [],
            "description": "Kubernetes backend: its namespaces, one per environment.",
            "items": {
              "$ref": "#/components/schemas/KubernetesNamespace"
            },
            "title": "Kubernetes Namespaces",
            "type": "array"
          },
          "secret_paths": {
            "default": [],
            "description": "dev and uat only. A VM-backend project's paths embed its machines' host names and are not listed.",
            "items": {
              "$ref": "#/components/schemas/SecretPath"
            },
            "title": "Secret Paths",
            "type": "array"
          },
          "urls": {
            "$ref": "#/components/schemas/ProjectUrls",
            "description": "The project's public URLs."
          }
        },
        "required": [
          "urls"
        ],
        "title": "ProjectOutputs",
        "type": "object"
      },
      "ProjectPage": {
        "description": "One page of projects (summaries: read one project for its `outputs`). `next_cursor` reads\nthe next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/ProjectSummary"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "ProjectPage",
        "type": "object"
      },
      "ProjectPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. Frozen members are accepted only with the\ncurrent value. `status` is not writable in v1.",
        "properties": {
          "allow_public_https_egress": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Kubernetes projects: allow egress to public HTTPS.",
            "title": "Allow Public Https Egress"
          },
          "api_exposure": {
            "anyOf": [
              {
                "enum": [
                  "INTERNAL_ONLY",
                  "PUBLIC"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who reaches the PROD API: `INTERNAL_ONLY` (default) or `PUBLIC`. The UAT and DEV APIs are never public.",
            "title": "Api Exposure"
          },
          "app_gateway": {
            "anyOf": [
              {
                "enum": [
                  "shared",
                  "dedicated"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`shared` rides the environment's app gateway; `dedicated` gets its own.",
            "title": "App Gateway"
          },
          "deployment_backend": {
            "anyOf": [
              {
                "enum": [
                  "vm",
                  "k8s"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Deployment Backend"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Description"
          },
          "enable_ai": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "An AI endpoint at `ai.<primary_domain>`. Also allows outbound HTTPS to the internet, as `allow_public_https_egress` does.",
            "title": "Enable Ai"
          },
          "enable_cache": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "An in-memory key-value cache.",
            "title": "Enable Cache"
          },
          "enable_dr_db_replica": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "A disaster-recovery replica of the PROD database.",
            "title": "Enable Dr Db Replica"
          },
          "enable_dr_object_storage_mirror": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "A disaster-recovery mirror of the PROD object storage.",
            "title": "Enable Dr Object Storage Mirror"
          },
          "enable_fullstack_app": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "An application: its front end at `app.<primary_domain>` and its API at `api.<primary_domain>`, in PROD, UAT and DEV.",
            "title": "Enable Fullstack App"
          },
          "enable_iis": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "IIS/.NET hosting. VM backend only.",
            "title": "Enable Iis"
          },
          "enable_mssql": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "SQL Server. VM backend only.",
            "title": "Enable Mssql"
          },
          "enable_nas_object_storage_replication": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Replication of the object storage to the central store: recorded, not acted on yet.",
            "title": "Enable Nas Object Storage Replication"
          },
          "enable_object_storage": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Object storage for the project; false provisions none (a database-only project).",
            "title": "Enable Object Storage"
          },
          "enable_static_site": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "A web site at `www.<primary_domain>` (and `uat.www.`, `dev.www.`), seeded from `www_template`.",
            "title": "Enable Static Site"
          },
          "enable_uat_app_public": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Make the UAT front end (`uat.app.`) reachable from the internet, e.g. to share a preview. DEV is never public.",
            "title": "Enable Uat App Public"
          },
          "enable_uat_www_public": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Make the UAT web site (`uat.www.`) reachable from the internet.",
            "title": "Enable Uat Www Public"
          },
          "enable_web_www": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "The web site ships from its own `<gitlab_repo_slug>-www` repository. Provisioning does not read it: the web site, its repository and its stages follow `enable_static_site` alone. With `false`, the platform's security scans leave the web site out, and a project with no application drops out of the traffic views. Keep it `true` (the default) unless the web site is not built from that repository.",
            "title": "Enable Web Www"
          },
          "frontend_exposure": {
            "anyOf": [
              {
                "enum": [
                  "INTERNAL_ONLY",
                  "PUBLIC"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who reaches the PROD front end: `PUBLIC` (the internet; default) or `INTERNAL_ONLY`.",
            "title": "Frontend Exposure"
          },
          "frontend_variant": {
            "anyOf": [
              {
                "enum": [
                  "react",
                  "angular",
                  "vue",
                  "nuxt4"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The front-end framework the application is generated with: `react` (default), `angular`, `vue` or `nuxt4`.",
            "title": "Frontend Variant"
          },
          "github_repo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub repository URL, recorded in the project's manifest as its mirror. null clears it.",
            "title": "Github Repo Url"
          },
          "github_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub user name, recorded with the project. null clears it.",
            "title": "Github User"
          },
          "gitlab_repo_slug": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Gitlab Repo Slug"
          },
          "has_mobile": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "The project has a mobile app. Its PROD API is then public whatever `api_exposure` says: the app calls it from the internet.",
            "title": "Has Mobile"
          },
          "import_existing_repo": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "The GitLab repository already holds code: provisioning does not seed it from the template.",
            "title": "Import Existing Repo"
          },
          "long_name": {
            "anyOf": [
              {
                "maxLength": 60,
                "minLength": 2,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The project's display name, 2-60 characters. Double quotes, apostrophes, backslashes and control characters are refused: the name is written into the project's generated files.",
            "title": "Long Name"
          },
          "mssql_edition": {
            "anyOf": [
              {
                "enum": [
                  "express",
                  "standard",
                  "enterprise"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The SQL Server edition PROD and UAT run, with `enable_mssql`: `express` (default; free), `standard` or `enterprise` (licensed through the platform operator).",
            "title": "Mssql Edition"
          },
          "network_only": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Network Only"
          },
          "primary_domain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Primary Domain"
          },
          "prod_object_storage_disks_per_vm": {
            "anyOf": [
              {
                "enum": [
                  1,
                  2
                ],
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Data disks per PROD object storage node.",
            "title": "Prod Object Storage Disks Per Vm"
          },
          "prod_object_storage_node_count": {
            "anyOf": [
              {
                "enum": [
                  2,
                  4
                ],
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "PROD object storage nodes. With `enable_object_storage`, nodes times `prod_object_storage_disks_per_vm` must be at least 4.",
            "title": "Prod Object Storage Node Count"
          },
          "project_index": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Project Index"
          },
          "short_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Short Name"
          },
          "tenant_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Tenant Id"
          },
          "windows_vm_count_dev": {
            "anyOf": [
              {
                "maximum": 10.0,
                "minimum": 0.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Windows Server VMs in DEV, 0-10. VM backend only.",
            "title": "Windows Vm Count Dev"
          },
          "windows_vm_count_prod": {
            "anyOf": [
              {
                "maximum": 10.0,
                "minimum": 0.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Windows Server VMs in PROD, 0-10. VM backend only.",
            "title": "Windows Vm Count Prod"
          },
          "windows_vm_count_uat": {
            "anyOf": [
              {
                "maximum": 10.0,
                "minimum": 0.0,
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Windows Server VMs in UAT, 0-10. VM backend only.",
            "title": "Windows Vm Count Uat"
          },
          "www_template": {
            "anyOf": [
              {
                "enum": [
                  "template-www",
                  "template-blog"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What seeds the web site's repository: `template-www` (an information site; default) or `template-blog` (articles in Markdown, with feeds). Ignored without `enable_static_site`.",
            "title": "Www Template"
          }
        },
        "title": "ProjectPatch",
        "type": "object"
      },
      "ProjectSummary": {
        "description": "A project as a list shows it: no `outputs`, no settings.",
        "properties": {
          "created_at": {
            "description": "When the project was registered.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The tenant's customer; null only for a tenant no customer owns.",
            "title": "Customer Id"
          },
          "deployment_backend": {
            "description": "`k8s` (default): namespaces on the shared Kubernetes clusters; `vm`: virtual machines of its own. Frozen.",
            "enum": [
              "vm",
              "k8s"
            ],
            "title": "Deployment Backend",
            "type": "string"
          },
          "gitlab_repo_slug": {
            "description": "The repository name in the customer's GitLab group. Frozen.",
            "title": "Gitlab Repo Slug",
            "type": "string"
          },
          "id": {
            "description": "The project's id.",
            "title": "Id",
            "type": "string"
          },
          "is_self": {
            "description": "One of ATAILA's own platform projects: readable, never writable through v1.",
            "title": "Is Self",
            "type": "boolean"
          },
          "long_name": {
            "description": "The project's display name, 2-60 characters. Double quotes, apostrophes, backslashes and control characters are refused: the name is written into the project's generated files.",
            "title": "Long Name",
            "type": "string"
          },
          "network_only": {
            "description": "Only the network zone is registered: no application and no web site. Frozen.",
            "title": "Network Only",
            "type": "boolean"
          },
          "primary_domain": {
            "description": "The domain the project's sites are named under (`www.`, `app.`, `api.`, `ai.`). Frozen.",
            "title": "Primary Domain",
            "type": "string"
          },
          "project_index": {
            "description": "The third octet of the project's networks; unique on the platform. Frozen.",
            "title": "Project Index",
            "type": "integer"
          },
          "short_name": {
            "description": "Lowercase letters and digits, unique on the platform. Frozen.",
            "title": "Short Name",
            "type": "string"
          },
          "status": {
            "description": "Read-only. `planned` until provisioning starts, `active` once every stage is done; also `provisioning`, `paused` and `retired`.",
            "enum": [
              "planned",
              "provisioning",
              "active",
              "paused",
              "retired"
            ],
            "title": "Status",
            "type": "string"
          },
          "tenant_id": {
            "description": "The owning tenant. Frozen.",
            "title": "Tenant Id",
            "type": "string"
          }
        },
        "required": [
          "id",
          "tenant_id",
          "customer_id",
          "project_index",
          "short_name",
          "long_name",
          "primary_domain",
          "gitlab_repo_slug",
          "deployment_backend",
          "network_only",
          "status",
          "is_self",
          "created_at"
        ],
        "title": "ProjectSummary",
        "type": "object"
      },
      "ProjectUpdated": {
        "description": "The project after a change, with the provisioning stages the change left\nstale.",
        "properties": {
          "allow_public_https_egress": {
            "default": false,
            "description": "Kubernetes projects: allow egress to public HTTPS.",
            "title": "Allow Public Https Egress",
            "type": "boolean"
          },
          "api_exposure": {
            "default": "INTERNAL_ONLY",
            "description": "Who reaches the PROD API: `INTERNAL_ONLY` (default) or `PUBLIC`. The UAT and DEV APIs are never public.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Api Exposure",
            "type": "string"
          },
          "app_gateway": {
            "default": "shared",
            "description": "`shared` rides the environment's app gateway; `dedicated` gets its own.",
            "enum": [
              "shared",
              "dedicated"
            ],
            "title": "App Gateway",
            "type": "string"
          },
          "created_at": {
            "description": "When the project was registered.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The tenant's customer; null only for a tenant no customer owns.",
            "title": "Customer Id"
          },
          "deployment_backend": {
            "description": "`k8s` (default): namespaces on the shared Kubernetes clusters; `vm`: virtual machines of its own. Frozen.",
            "enum": [
              "vm",
              "k8s"
            ],
            "title": "Deployment Backend",
            "type": "string"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters.",
            "title": "Description"
          },
          "enable_ai": {
            "default": false,
            "description": "An AI endpoint at `ai.<primary_domain>`. Also allows outbound HTTPS to the internet, as `allow_public_https_egress` does.",
            "title": "Enable Ai",
            "type": "boolean"
          },
          "enable_cache": {
            "default": false,
            "description": "An in-memory key-value cache.",
            "title": "Enable Cache",
            "type": "boolean"
          },
          "enable_dr_db_replica": {
            "default": true,
            "description": "A disaster-recovery replica of the PROD database.",
            "title": "Enable Dr Db Replica",
            "type": "boolean"
          },
          "enable_dr_object_storage_mirror": {
            "default": true,
            "description": "A disaster-recovery mirror of the PROD object storage.",
            "title": "Enable Dr Object Storage Mirror",
            "type": "boolean"
          },
          "enable_fullstack_app": {
            "default": true,
            "description": "An application: its front end at `app.<primary_domain>` and its API at `api.<primary_domain>`, in PROD, UAT and DEV.",
            "title": "Enable Fullstack App",
            "type": "boolean"
          },
          "enable_iis": {
            "default": false,
            "description": "IIS/.NET hosting. VM backend only.",
            "title": "Enable Iis",
            "type": "boolean"
          },
          "enable_mssql": {
            "default": false,
            "description": "SQL Server. VM backend only.",
            "title": "Enable Mssql",
            "type": "boolean"
          },
          "enable_nas_object_storage_replication": {
            "default": false,
            "description": "Replication of the object storage to the central store: recorded, not acted on yet.",
            "title": "Enable Nas Object Storage Replication",
            "type": "boolean"
          },
          "enable_object_storage": {
            "default": true,
            "description": "Object storage for the project; false provisions none (a database-only project).",
            "title": "Enable Object Storage",
            "type": "boolean"
          },
          "enable_static_site": {
            "default": true,
            "description": "A web site at `www.<primary_domain>` (and `uat.www.`, `dev.www.`), seeded from `www_template`.",
            "title": "Enable Static Site",
            "type": "boolean"
          },
          "enable_uat_app_public": {
            "default": false,
            "description": "Make the UAT front end (`uat.app.`) reachable from the internet, e.g. to share a preview. DEV is never public.",
            "title": "Enable Uat App Public",
            "type": "boolean"
          },
          "enable_uat_www_public": {
            "default": false,
            "description": "Make the UAT web site (`uat.www.`) reachable from the internet.",
            "title": "Enable Uat Www Public",
            "type": "boolean"
          },
          "enable_web_www": {
            "default": true,
            "description": "The web site ships from its own `<gitlab_repo_slug>-www` repository. Provisioning does not read it: the web site, its repository and its stages follow `enable_static_site` alone. With `false`, the platform's security scans leave the web site out, and a project with no application drops out of the traffic views. Keep it `true` (the default) unless the web site is not built from that repository.",
            "title": "Enable Web Www",
            "type": "boolean"
          },
          "frontend_exposure": {
            "default": "PUBLIC",
            "description": "Who reaches the PROD front end: `PUBLIC` (the internet; default) or `INTERNAL_ONLY`.",
            "enum": [
              "INTERNAL_ONLY",
              "PUBLIC"
            ],
            "title": "Frontend Exposure",
            "type": "string"
          },
          "frontend_variant": {
            "default": "react",
            "description": "The front-end framework the application is generated with: `react` (default), `angular`, `vue` or `nuxt4`.",
            "enum": [
              "react",
              "angular",
              "vue",
              "nuxt4"
            ],
            "title": "Frontend Variant",
            "type": "string"
          },
          "github_repo_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub repository URL, recorded in the project's manifest as its mirror.",
            "title": "Github Repo Url"
          },
          "github_user": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A GitHub user name, recorded with the project.",
            "title": "Github User"
          },
          "gitlab_repo_slug": {
            "description": "The repository name in the customer's GitLab group. Frozen.",
            "title": "Gitlab Repo Slug",
            "type": "string"
          },
          "has_mobile": {
            "default": false,
            "description": "The project has a mobile app. Its PROD API is then public whatever `api_exposure` says: the app calls it from the internet.",
            "title": "Has Mobile",
            "type": "boolean"
          },
          "id": {
            "description": "The project's id.",
            "title": "Id",
            "type": "string"
          },
          "import_existing_repo": {
            "default": false,
            "description": "The GitLab repository already holds code: provisioning does not seed it from the template.",
            "title": "Import Existing Repo",
            "type": "boolean"
          },
          "is_self": {
            "description": "One of ATAILA's own platform projects: readable, never writable through v1.",
            "title": "Is Self",
            "type": "boolean"
          },
          "long_name": {
            "description": "The project's display name, 2-60 characters. Double quotes, apostrophes, backslashes and control characters are refused: the name is written into the project's generated files.",
            "maxLength": 60,
            "minLength": 2,
            "title": "Long Name",
            "type": "string"
          },
          "mssql_edition": {
            "default": "express",
            "description": "The SQL Server edition PROD and UAT run, with `enable_mssql`: `express` (default; free), `standard` or `enterprise` (licensed through the platform operator).",
            "enum": [
              "express",
              "standard",
              "enterprise"
            ],
            "title": "Mssql Edition",
            "type": "string"
          },
          "network_only": {
            "description": "Only the network zone is registered: no application and no web site. Frozen.",
            "title": "Network Only",
            "type": "boolean"
          },
          "outputs": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProjectOutputs"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the project's compiled manifest names; null for a project registered without one."
          },
          "primary_domain": {
            "description": "The domain the project's sites are named under (`www.`, `app.`, `api.`, `ai.`). Frozen.",
            "title": "Primary Domain",
            "type": "string"
          },
          "prod_object_storage_disks_per_vm": {
            "default": 2,
            "description": "Data disks per PROD object storage node.",
            "enum": [
              1,
              2
            ],
            "title": "Prod Object Storage Disks Per Vm",
            "type": "integer"
          },
          "prod_object_storage_node_count": {
            "default": 2,
            "description": "PROD object storage nodes. With `enable_object_storage`, nodes times `prod_object_storage_disks_per_vm` must be at least 4.",
            "enum": [
              2,
              4
            ],
            "title": "Prod Object Storage Node Count",
            "type": "integer"
          },
          "project_index": {
            "description": "The third octet of the project's networks; unique on the platform. Frozen.",
            "title": "Project Index",
            "type": "integer"
          },
          "registered_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the user (a person or a service account) who registered the project; null when that was not recorded.",
            "title": "Registered By"
          },
          "short_name": {
            "description": "Lowercase letters and digits, unique on the platform. Frozen.",
            "title": "Short Name",
            "type": "string"
          },
          "stale_stages": {
            "default": [],
            "description": "The provisioning stages this change left stale, in apply order: stages already done whose substrate the change affects. `POST /projects/{id}/provisioning` re-applies them.",
            "items": {
              "type": "string"
            },
            "title": "Stale Stages",
            "type": "array"
          },
          "status": {
            "description": "Read-only. `planned` until provisioning starts, `active` once every stage is done; also `provisioning`, `paused` and `retired`.",
            "enum": [
              "planned",
              "provisioning",
              "active",
              "paused",
              "retired"
            ],
            "title": "Status",
            "type": "string"
          },
          "tenant_id": {
            "description": "The owning tenant. Frozen.",
            "title": "Tenant Id",
            "type": "string"
          },
          "warnings": {
            "default": [],
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          },
          "windows_vm_count_dev": {
            "default": 0,
            "description": "Windows Server VMs in DEV, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Dev",
            "type": "integer"
          },
          "windows_vm_count_prod": {
            "default": 0,
            "description": "Windows Server VMs in PROD, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Prod",
            "type": "integer"
          },
          "windows_vm_count_uat": {
            "default": 0,
            "description": "Windows Server VMs in UAT, 0-10. VM backend only.",
            "maximum": 10.0,
            "minimum": 0.0,
            "title": "Windows Vm Count Uat",
            "type": "integer"
          },
          "www_template": {
            "default": "template-www",
            "description": "What seeds the web site's repository: `template-www` (an information site; default) or `template-blog` (articles in Markdown, with feeds). Ignored without `enable_static_site`.",
            "enum": [
              "template-www",
              "template-blog"
            ],
            "title": "Www Template",
            "type": "string"
          }
        },
        "required": [
          "long_name",
          "id",
          "tenant_id",
          "customer_id",
          "project_index",
          "short_name",
          "gitlab_repo_slug",
          "primary_domain",
          "deployment_backend",
          "network_only",
          "status",
          "is_self",
          "registered_by",
          "created_at"
        ],
        "title": "ProjectUpdated",
        "type": "object"
      },
      "ProjectUrls": {
        "description": "The project's public URLs; null where the project has no such site.",
        "properties": {
          "ai": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The AI endpoint (`ai.`).",
            "title": "Ai"
          },
          "backend": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The application API (`api.`).",
            "title": "Backend"
          },
          "frontend": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The application front end (`app.`).",
            "title": "Frontend"
          },
          "static": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The public web site (`www.`).",
            "title": "Static"
          }
        },
        "title": "ProjectUrls",
        "type": "object"
      },
      "Provisioning": {
        "description": "Where a project's provisioning stands, from the database only: the\nstages on its apply path (deferred ones left out), which are done, running,\nfailed, stale or waiting for an operator, and the orchestration walking\nthem, if any.",
        "properties": {
          "converged": {
            "description": "Every stage is done and none is stale — done by a real or by a simulated run.",
            "title": "Converged",
            "type": "boolean"
          },
          "dispatch_mode": {
            "description": "`dryrun`: this platform fakes pipeline dispatch, so no stage is ever executed and provisioning never completes. `simulate`: each stage is marked done after a few seconds without running, so a walk can reach `converged` while `provisioned` stays false.",
            "enum": [
              "live",
              "dryrun",
              "simulate"
            ],
            "title": "Dispatch Mode",
            "type": "string"
          },
          "done": {
            "description": "Of those, the stages whose latest run succeeded.",
            "title": "Done",
            "type": "integer"
          },
          "failed_stages": {
            "description": "The keys of the stages whose latest run failed.",
            "items": {
              "type": "string"
            },
            "title": "Failed Stages",
            "type": "array"
          },
          "message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Under `dryrun` or `simulate`: what that means for this project's provisioning, for a person; null under `live`.",
            "title": "Message"
          },
          "needs_action_stages": {
            "description": "The keys of the stages waiting for an operator in the portal (`manual`).",
            "items": {
              "type": "string"
            },
            "title": "Needs Action Stages",
            "type": "array"
          },
          "orchestration": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Orchestration"
              },
              {
                "type": "null"
              }
            ],
            "description": "The orchestration running on the project, if any."
          },
          "percent": {
            "description": "Done stages as a share of `total`, 0-100, rounded.",
            "title": "Percent",
            "type": "integer"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          },
          "provisioned": {
            "description": "Converged, and on real runs only: no stage is simulated. The one field that says the substrate exists.",
            "title": "Provisioned",
            "type": "boolean"
          },
          "running_stages": {
            "description": "The keys of the stages running now.",
            "items": {
              "type": "string"
            },
            "title": "Running Stages",
            "type": "array"
          },
          "simulated": {
            "description": "At least one stage's latest run was SIMULATED (`dispatch_mode` `simulate`): marked done, never run.",
            "title": "Simulated",
            "type": "boolean"
          },
          "stages": {
            "description": "Every stage that counts, in catalogue order.",
            "items": {
              "$ref": "#/components/schemas/StageState"
            },
            "title": "Stages",
            "type": "array"
          },
          "stale_stages": {
            "description": "The keys of the stages done against an older manifest, in apply order: the next provisioning start re-applies exactly these.",
            "items": {
              "type": "string"
            },
            "title": "Stale Stages",
            "type": "array"
          },
          "state": {
            "description": "`not_started` (no stage done), `provisioning` (some done or running), `complete` (every stage done), `attention` (a stage failed) or `needs_action` (a stage needs an operator in the portal). A failure outranks a stage needing an operator. Deferred stages do not count.",
            "enum": [
              "not_started",
              "provisioning",
              "complete",
              "attention",
              "needs_action"
            ],
            "title": "State",
            "type": "string"
          },
          "total": {
            "description": "The stages that count (every stage but the deferred ones).",
            "title": "Total",
            "type": "integer"
          }
        },
        "required": [
          "project_id",
          "state",
          "converged",
          "provisioned",
          "simulated",
          "percent",
          "total",
          "done",
          "stages",
          "running_stages",
          "failed_stages",
          "needs_action_stages",
          "stale_stages",
          "dispatch_mode"
        ],
        "title": "Provisioning",
        "type": "object"
      },
      "ReleaseOperation": {
        "description": "One release-management operation: a promotion (`promote_build`) or a data\ncopy (`copy_data`, booked in the portal only).",
        "properties": {
          "approval_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The requester's reason and the approver's note, as recorded.",
            "title": "Approval Reason"
          },
          "completed_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it ended (`succeeded` or `failed`); null until then.",
            "title": "Completed At"
          },
          "component": {
            "anyOf": [
              {
                "enum": [
                  "app-api",
                  "www"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What is promoted: `app-api` or `www`; null for a data copy.",
            "title": "Component"
          },
          "decided_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was approved or rejected; null when no person decided it.",
            "title": "Decided At"
          },
          "decided_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who approved or rejected it.",
            "title": "Decided By"
          },
          "error_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why it failed or was rejected. Host addresses and digests are masked.",
            "title": "Error Reason"
          },
          "id": {
            "description": "The release operation's id (`/release-operations/{id}`).",
            "title": "Id",
            "type": "string"
          },
          "operation": {
            "description": "`promote_build` (a promotion) or `copy_data` (a data copy, booked in the portal only).",
            "enum": [
              "promote_build",
              "copy_data"
            ],
            "title": "Operation",
            "type": "string"
          },
          "operation_id": {
            "description": "`release:<id>`, for `GET /operations/{operation_id}`.",
            "title": "Operation Id",
            "type": "string"
          },
          "pipeline_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The pipeline that carries it out, once known.",
            "title": "Pipeline Url"
          },
          "portal_status": {
            "description": "Release management's own status.",
            "enum": [
              "pending",
              "approved",
              "rejected",
              "running",
              "succeeded",
              "failed"
            ],
            "title": "Portal Status",
            "type": "string"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          },
          "requested_at": {
            "description": "When it was requested.",
            "format": "date-time",
            "title": "Requested At",
            "type": "string"
          },
          "requested_by": {
            "description": "E-mail of the principal that asked (for a service account, its service address), or `ci:<repo>@<commit>`.",
            "title": "Requested By",
            "type": "string"
          },
          "requested_token_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The API token used, when one was.",
            "title": "Requested Token Id"
          },
          "requested_via": {
            "anyOf": [
              {
                "enum": [
                  "session",
                  "pat",
                  "service_account"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "How the request was made through /api/v1. Null: booked in the portal or by a pipeline.",
            "title": "Requested Via"
          },
          "source_env": {
            "description": "Where it comes from: the environment below the target (`sandbox` for `dev`, where a named build is deployed; `dev` for `uat`; `uat` for `prod`).",
            "enum": [
              "sandbox",
              "dev",
              "uat",
              "prod"
            ],
            "title": "Source Env",
            "type": "string"
          },
          "started_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the pipeline started carrying it out; null until then.",
            "title": "Started At"
          },
          "status": {
            "description": "`awaiting_approval`: a PROD request waiting for a person in the portal. `pending`: approved, not yet picked up. `failed` also covers a rejected request (`portal_status` = `rejected`) and an operation the portal gave up on after hearing nothing (`error_reason` says so).",
            "enum": [
              "pending",
              "awaiting_approval",
              "running",
              "succeeded",
              "failed"
            ],
            "title": "Status",
            "type": "string"
          },
          "target_env": {
            "description": "Where it goes.",
            "enum": [
              "sandbox",
              "dev",
              "uat",
              "prod"
            ],
            "title": "Target Env",
            "type": "string"
          },
          "version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The version promoted (an image tag); null for a data copy.",
            "title": "Version"
          }
        },
        "required": [
          "id",
          "operation_id",
          "project_id",
          "operation",
          "source_env",
          "target_env",
          "status",
          "portal_status",
          "requested_by",
          "requested_at"
        ],
        "title": "ReleaseOperation",
        "type": "object"
      },
      "ReleaseOperationPage": {
        "description": "One page of a project's release operations, newest first. `next_cursor` reads the\nnext page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/ReleaseOperation"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "ReleaseOperationPage",
        "type": "object"
      },
      "ReleasePromotionCreate": {
        "additionalProperties": false,
        "description": "Request a promotion of one component into one environment.\n\n`dev` deploys a named build and needs `version`; the API cannot verify that the\nbuild exists before dispatch. `uat` and `prod` promote what the\nenvironment below LAST REPORTED running (`dev` for `uat`, `uat` for `prod`):\nomit `version` to take it, or give it and it must be that version.",
        "properties": {
          "component": {
            "description": "What to promote: `app-api` (the application and its API) or `www` (the web site).",
            "enum": [
              "app-api",
              "www"
            ],
            "title": "Component",
            "type": "string"
          },
          "target_env": {
            "description": "Where to: `dev`, `uat` or `prod`. A `prod` promotion waits for a person to approve it in the portal.",
            "enum": [
              "dev",
              "uat",
              "prod"
            ],
            "title": "Target Env",
            "type": "string"
          },
          "version": {
            "anyOf": [
              {
                "pattern": "^[A-Za-z0-9_][A-Za-z0-9_.-]{0,63}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Required for `dev`, where it names a build that the API cannot verify exists before dispatch. For `uat` and `prod`: omitted means the version the source environment last reported; given, it must equal that version (422 `version_not_at_source` otherwise).",
            "title": "Version"
          }
        },
        "required": [
          "component",
          "target_env"
        ],
        "title": "ReleasePromotionCreate",
        "type": "object"
      },
      "ReleaseState": {
        "description": "Where a project's releases stand: what each environment last reported\nrunning, the PROD data lock, and the release operations still open.",
        "properties": {
          "deployment_backend": {
            "description": "Only `k8s` projects accept promotion requests through the API.",
            "enum": [
              "k8s",
              "vm"
            ],
            "title": "Deployment Backend",
            "type": "string"
          },
          "in_flight_operation_ids": {
            "description": "`release:<id>` of every operation approved or running.",
            "items": {
              "type": "string"
            },
            "title": "In Flight Operation Ids",
            "type": "array"
          },
          "pending_operation_ids": {
            "description": "`release:<id>` of every operation awaiting approval.",
            "items": {
              "type": "string"
            },
            "title": "Pending Operation Ids",
            "type": "array"
          },
          "prior_prod_data_copies": {
            "description": "Succeeded data copies into PROD, all time.",
            "title": "Prior Prod Data Copies",
            "type": "integer"
          },
          "prod_data_locked": {
            "description": "The PROD DATA lock: while set, no data copy may target PROD. It does not block code promotion.",
            "title": "Prod Data Locked",
            "type": "boolean"
          },
          "prod_data_locked_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the PROD data lock was set; null while it is not.",
            "title": "Prod Data Locked At"
          },
          "prod_data_locked_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Who set the PROD data lock (an e-mail address, as recorded); null while it is not set.",
            "title": "Prod Data Locked By"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          },
          "versions": {
            "description": "Last reported versions, per environment and component.",
            "items": {
              "$ref": "#/components/schemas/ReportedVersion"
            },
            "title": "Versions",
            "type": "array"
          }
        },
        "required": [
          "project_id",
          "deployment_backend",
          "versions",
          "prod_data_locked",
          "prior_prod_data_copies",
          "pending_operation_ids",
          "in_flight_operation_ids"
        ],
        "title": "ReleaseState",
        "type": "object"
      },
      "ReportedVersion": {
        "description": "What a release pipeline LAST REPORTED for one environment and component.\nNot a live probe: the portal records it when a deploy reports success.",
        "properties": {
          "component": {
            "description": "`app-api` (the application and its API), `www` (the web site) or `database`.",
            "enum": [
              "app-api",
              "www",
              "database"
            ],
            "title": "Component",
            "type": "string"
          },
          "env": {
            "description": "The environment.",
            "enum": [
              "sandbox",
              "dev",
              "uat",
              "prod"
            ],
            "title": "Env",
            "type": "string"
          },
          "last_reported_at": {
            "description": "When it reported it.",
            "format": "date-time",
            "title": "Last Reported At",
            "type": "string"
          },
          "last_reported_by": {
            "description": "An operator's e-mail or `pipeline:<id>`.",
            "title": "Last Reported By",
            "type": "string"
          },
          "last_reported_version": {
            "description": "The version the pipeline reported running.",
            "title": "Last Reported Version",
            "type": "string"
          },
          "source_env": {
            "anyOf": [
              {
                "enum": [
                  "sandbox",
                  "dev",
                  "uat",
                  "prod"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The environment it was promoted from.",
            "title": "Source Env"
          }
        },
        "required": [
          "env",
          "component",
          "last_reported_version",
          "last_reported_at",
          "last_reported_by"
        ],
        "title": "ReportedVersion",
        "type": "object"
      },
      "RoleGrant": {
        "description": "A role a person holds.",
        "properties": {
          "granted_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was granted; null when that was not recorded.",
            "title": "Granted At"
          },
          "role": {
            "description": "The role's name as the roles catalogue spells it: a permission key (`GET /permissions`) or a role name such as `user` or `admin`.",
            "title": "Role",
            "type": "string"
          },
          "user_id": {
            "description": "The person.",
            "title": "User Id",
            "type": "string"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          }
        },
        "required": [
          "user_id",
          "role"
        ],
        "title": "RoleGrant",
        "type": "object"
      },
      "RoleGrantPage": {
        "description": "One page of a user's role grants. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/RoleGrant"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "RoleGrantPage",
        "type": "object"
      },
      "SecretPath": {
        "description": "Where one non-production environment of the project keeps its secrets in\nthe platform's secrets store.",
        "properties": {
          "env": {
            "description": "The environment: `dev` or `uat`.",
            "enum": [
              "dev",
              "uat"
            ],
            "title": "Env",
            "type": "string"
          },
          "path": {
            "description": "The location in the secrets store.",
            "title": "Path",
            "type": "string"
          }
        },
        "required": [
          "env",
          "path"
        ],
        "title": "SecretPath",
        "type": "object"
      },
      "ServingTier": {
        "description": "A serving tier: a stable capability name (`general`, `code`, …) that\nclients call as the model name, backed at any moment by one loaded model:\nthe pinned one, or one assigned automatically from the tier's category.\nTiers exist only as the platform ships them; a client can pin, unpin,\nenable and disable one.",
        "properties": {
          "candidate_models": {
            "description": "Every model loaded on the fleet right now: the values `pinned_model` may take without `allow_unloaded_pin`.",
            "items": {
              "type": "string"
            },
            "title": "Candidate Models",
            "type": "array"
          },
          "category": {
            "description": "The group automatic assignment picks a model from, e.g. `chat`, `code`, `reason`, `vision`, `embed` or `agent`. Other values may appear.",
            "title": "Category",
            "type": "string"
          },
          "created_at": {
            "description": "When the tier entered the catalogue.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "enabled": {
            "description": "The tier is offered to clients. A disabled tier is never served, even when a model backs it.",
            "title": "Enabled",
            "type": "boolean"
          },
          "key": {
            "description": "The tier's name: the model name clients send to the gateway, and an entry of a key's `models`.",
            "title": "Key",
            "type": "string"
          },
          "label": {
            "description": "The name the portal shows for the tier.",
            "title": "Label",
            "type": "string"
          },
          "pinned_model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Served model name; null = auto-assign.",
            "title": "Pinned Model"
          },
          "resolved": {
            "description": "A loaded model backs the tier right now.",
            "title": "Resolved",
            "type": "boolean"
          },
          "resolved_model": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The served model backing it right now.",
            "title": "Resolved Model"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the tier is for, in a few words, e.g. `agentic coder`.",
            "title": "Role"
          },
          "sort": {
            "description": "The order within the category, lowest first; the first tier of a category is filled first when assigning automatically.",
            "title": "Sort",
            "type": "integer"
          },
          "source": {
            "description": "`pin`: the pin is loaded and serves; `auto`: auto-assigned; `pin-offline`: pinned to a model that is not loaded, so the tier is hidden; `none`: nothing serves it.",
            "enum": [
              "pin",
              "auto",
              "pin-offline",
              "none"
            ],
            "title": "Source",
            "type": "string"
          },
          "updated_at": {
            "description": "The last change; equal to `created_at` until the first change.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          }
        },
        "required": [
          "key",
          "label",
          "category",
          "sort",
          "pinned_model",
          "enabled",
          "resolved",
          "resolved_model",
          "source",
          "candidate_models",
          "created_at",
          "updated_at"
        ],
        "title": "ServingTier",
        "type": "object"
      },
      "ServingTierPage": {
        "description": "One page of serving tiers. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/ServingTier"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "ServingTierPage",
        "type": "object"
      },
      "ServingTierPut": {
        "additionalProperties": false,
        "description": "Set the pin and/or the enabled flag of an EXISTING tier (tiers exist\nonly by migration). An omitted member is left unchanged.",
        "properties": {
          "allow_unloaded_pin": {
            "default": false,
            "description": "Accept a `pinned_model` that is not loaded. The tier then serves nothing, and the gateway drops it, until that model is loaded.",
            "title": "Allow Unloaded Pin",
            "type": "boolean"
          },
          "enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "false hides the tier from every client.",
            "title": "Enabled"
          },
          "pinned_model": {
            "anyOf": [
              {
                "pattern": "^[A-Za-z0-9._:/@+-]{1,200}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "A served model name, or null to return the tier to auto-assign. A name that is not in `candidate_models` is refused (`model_not_loaded`) unless `allow_unloaded_pin` is true; sending the tier's CURRENT pin is always accepted.",
            "title": "Pinned Model"
          }
        },
        "title": "ServingTierPut",
        "type": "object"
      },
      "SocketChain": {
        "description": "Whether the census history is intact: each row's hash covers its content\nand the row before it, so a rewritten history shows.",
        "properties": {
          "first_broken_row": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the first census row that does not match, when not intact.",
            "title": "First Broken Row"
          },
          "intact": {
            "description": "Every row's hash matches its content and its predecessor.",
            "title": "Intact",
            "type": "boolean"
          },
          "rows": {
            "description": "Census rows in the hash chain.",
            "title": "Rows",
            "type": "integer"
          }
        },
        "required": [
          "rows",
          "intact",
          "first_broken_row"
        ],
        "title": "SocketChain",
        "type": "object"
      },
      "SocketFact": {
        "description": "The latest census measurement of one node.",
        "properties": {
          "cluster": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The virtualisation cluster the node belongs to, e.g. `prod` or `nonprod`; null when not recorded.",
            "title": "Cluster"
          },
          "cores_per_socket": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cores per socket, when measured.",
            "title": "Cores Per Socket"
          },
          "measured_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was measured.",
            "title": "Measured At"
          },
          "node_name": {
            "description": "The node's name in its cluster.",
            "title": "Node Name",
            "type": "string"
          },
          "sockets": {
            "description": "CPU sockets measured on the node; never zero.",
            "title": "Sockets",
            "type": "integer"
          },
          "source": {
            "description": "Where the count came from: today always the virtualisation cluster's own report of the node. Other values may appear.",
            "title": "Source",
            "type": "string"
          }
        },
        "required": [
          "node_name",
          "sockets",
          "source"
        ],
        "title": "SocketFact",
        "type": "object"
      },
      "SocketFacts": {
        "description": "The socket census: what the latest measurement of each node found, and\nwhether the census history is intact.",
        "properties": {
          "chain": {
            "$ref": "#/components/schemas/SocketChain",
            "description": "The census history's hash chain."
          },
          "facts": {
            "description": "The latest measurement per node.",
            "items": {
              "$ref": "#/components/schemas/SocketFact"
            },
            "title": "Facts",
            "type": "array"
          },
          "total": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Sum of `sockets` over `facts`; null when no census has run.",
            "title": "Total"
          }
        },
        "required": [
          "facts",
          "total",
          "chain"
        ],
        "title": "SocketFacts",
        "type": "object"
      },
      "StageGrid": {
        "description": "Every provisioning stage of the project, deferred ones included, as the\nportal's Plan page shows them, from the database only.",
        "properties": {
          "percent": {
            "description": "Done stages as a share of `total`, 0-100, rounded.",
            "title": "Percent",
            "type": "integer"
          },
          "project_id": {
            "description": "The project.",
            "title": "Project Id",
            "type": "string"
          },
          "stages": {
            "description": "Every stage, in catalogue order.",
            "items": {
              "$ref": "#/components/schemas/StageGridItem"
            },
            "title": "Stages",
            "type": "array"
          },
          "state": {
            "description": "`not_started` (no stage done), `provisioning` (some done or running), `complete` (every stage done), `attention` (a stage failed) or `needs_action` (a stage needs an operator in the portal). A failure outranks a stage needing an operator. Deferred stages do not count.",
            "enum": [
              "not_started",
              "provisioning",
              "complete",
              "attention",
              "needs_action"
            ],
            "title": "State",
            "type": "string"
          }
        },
        "required": [
          "project_id",
          "state",
          "percent",
          "stages"
        ],
        "title": "StageGrid",
        "type": "object"
      },
      "StageGridItem": {
        "description": "One stage of the project's provisioning, as the portal's Plan page shows\nit.",
        "properties": {
          "blocked": {
            "description": "Pending, and a stage it depends on is not done.",
            "title": "Blocked",
            "type": "boolean"
          },
          "deferred": {
            "description": "Kept for visibility; never applied automatically.",
            "title": "Deferred",
            "type": "boolean"
          },
          "deps": {
            "description": "The keys of the stages it depends on.",
            "items": {
              "type": "string"
            },
            "title": "Deps",
            "type": "array"
          },
          "error_message": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Why the latest run failed, as it reported it.",
            "title": "Error Message"
          },
          "finished_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the latest run ended; null while it runs or when it has not.",
            "title": "Finished At"
          },
          "key": {
            "description": "The stage's key, stable across runs and the same as `Operation.stage`.",
            "title": "Key",
            "type": "string"
          },
          "last_run_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When that run was created (dispatched). Null exactly when `last_run_id` is.",
            "title": "Last Run At"
          },
          "last_run_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of this stage's newest provisioning run in the portal's run history: the run `status` is taken from. A run id, not an operation id (`/operations/provision:<id>` names the orchestration that walked the stages). Null when the stage has never run, or when its last success was undone by a later teardown (the stage then reads `pending`).",
            "title": "Last Run Id"
          },
          "simulated": {
            "default": false,
            "description": "Its latest run was simulated.",
            "title": "Simulated",
            "type": "boolean"
          },
          "stale": {
            "description": "Done against an older manifest; re-applied by the next provisioning start.",
            "title": "Stale",
            "type": "boolean"
          },
          "started_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the latest run started; null when it has not.",
            "title": "Started At"
          },
          "status": {
            "description": "`pending`, `running`, `success`, `failed`, `partial` or `manual` (the stage needs an operator).",
            "enum": [
              "pending",
              "running",
              "success",
              "failed",
              "partial",
              "manual"
            ],
            "title": "Status",
            "type": "string"
          },
          "title": {
            "description": "The stage's name, for a person.",
            "title": "Title",
            "type": "string"
          },
          "verify_state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The stage's latest verification, a check that what it provisioned is there: `pending`, `running`, `verified`, `not_verified` or `error`; null when never verified. Other values may appear.",
            "title": "Verify State"
          },
          "verify_summary": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What that verification found, for a person.",
            "title": "Verify Summary"
          }
        },
        "required": [
          "key",
          "title",
          "deps",
          "deferred",
          "status",
          "blocked",
          "stale"
        ],
        "title": "StageGridItem",
        "type": "object"
      },
      "StageState": {
        "description": "One provisioning stage of the project, and where it stands.",
        "properties": {
          "key": {
            "description": "The stage's key, stable across runs and the same as `Operation.stage`.",
            "title": "Key",
            "type": "string"
          },
          "last_run_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When that run was created (dispatched). Null exactly when `last_run_id` is.",
            "title": "Last Run At"
          },
          "last_run_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of this stage's newest provisioning run in the portal's run history: the run `status` is taken from. A run id, not an operation id (`/operations/provision:<id>` names the orchestration that walked the stages). Null when the stage has never run, or when its last success was undone by a later teardown (the stage then reads `pending`).",
            "title": "Last Run Id"
          },
          "simulated": {
            "default": false,
            "description": "Its latest run was simulated.",
            "title": "Simulated",
            "type": "boolean"
          },
          "stale": {
            "description": "Done against an older manifest; re-applied by the next provisioning start.",
            "title": "Stale",
            "type": "boolean"
          },
          "status": {
            "description": "`pending`, `running`, `success`, `failed`, `partial` or `manual` (the stage needs an operator).",
            "enum": [
              "pending",
              "running",
              "success",
              "failed",
              "partial",
              "manual"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "key",
          "status",
          "stale"
        ],
        "title": "StageState",
        "type": "object"
      },
      "Storage": {
        "description": "The model storage as last scanned: the central-store shares and each\nnode's local disk. Nothing is scanned by reading it.",
        "properties": {
          "captured_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The newest scan; null when nothing was ever scanned.",
            "title": "Captured At"
          },
          "nas": {
            "description": "Last scanned free space per share.",
            "items": {
              "$ref": "#/components/schemas/StorageMount"
            },
            "title": "Nas",
            "type": "array"
          },
          "nodes": {
            "description": "Last scanned local disk per node, with its cached models.",
            "items": {
              "$ref": "#/components/schemas/NodeStorage"
            },
            "title": "Nodes",
            "type": "array"
          },
          "shares": {
            "description": "The central-store shares the store actions can use.",
            "items": {
              "type": "string"
            },
            "title": "Shares",
            "type": "array"
          }
        },
        "required": [
          "shares",
          "nas",
          "nodes",
          "captured_at"
        ],
        "title": "Storage",
        "type": "object"
      },
      "StorageMount": {
        "description": "One storage location as last scanned: a central-store share, or a\nnode's local disk.",
        "properties": {
          "captured_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When it was last scanned; null when never.",
            "title": "Captured At"
          },
          "free_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free space in GB, as last scanned.",
            "title": "Free Gb"
          },
          "kind": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The kind of disk, as the scan reported it: `nvme`, `hdd` or `raid`. Other values may appear.",
            "title": "Kind"
          },
          "mount": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Where the storage is mounted, as the scan reported it.",
            "title": "Mount"
          },
          "name": {
            "description": "The share's name, or the node's hostname.",
            "title": "Name",
            "type": "string"
          },
          "total_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Total capacity in GB, as last scanned.",
            "title": "Total Gb"
          }
        },
        "required": [
          "name"
        ],
        "title": "StorageMount",
        "type": "object"
      },
      "StoreRun": {
        "description": "One run of the model store: a node cache or uncache started through\nthis API, or an action started in the portal. The same run is the\noperation `model-store-run:<id>`.",
        "properties": {
          "action": {
            "description": "`cache` / `uncache` (the two v1 starts), or a portal action: `pull`, `purge`, `rescan`, `gateway-deploy`, `gateway-restart`.",
            "title": "Action",
            "type": "string"
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What the run reported last, for a person: progress, or why it failed.",
            "title": "Detail"
          },
          "dispatch_mode": {
            "anyOf": [
              {
                "enum": [
                  "live",
                  "dryrun"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "`live`: the runner pipeline was triggered. `dryrun`: this estate fakes dispatch (sandbox, or dispatch mode `dryrun` or `simulate` — a store run is never simulated); the run holds a fake pipeline id and nothing ran. Null for runs started by the portal, which does not record it.",
            "title": "Dispatch Mode"
          },
          "finished_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the run ended (`success`, `failed` or `timeout`); null while it runs.",
            "title": "Finished At"
          },
          "id": {
            "description": "The run's id.",
            "title": "Id",
            "type": "string"
          },
          "job_started_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the runner job started. The run's time budget counts from here, not from the dispatch.",
            "title": "Job Started At"
          },
          "model_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The model the run is for; null for a run that is about no one model (`rescan`, `gateway-deploy`, `gateway-restart`).",
            "title": "Model Id"
          },
          "node": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The AI node the run works on (for `cache` and `uncache`, the node of the copy); null when no node is involved.",
            "title": "Node"
          },
          "operation_id": {
            "description": "`model-store-run:<id>`: poll it at /operations/{id}.",
            "title": "Operation Id",
            "type": "string"
          },
          "pipeline_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "The runner pipeline carrying the run out, once dispatched. Under `dryrun` a fake id.",
            "title": "Pipeline Id"
          },
          "pipeline_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The pipeline's page in GitLab, once known. Under `dryrun` it names the fake pipeline id and leads nowhere.",
            "title": "Pipeline Url"
          },
          "progress_gb": {
            "anyOf": [
              {
                "format": "double",
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "GB copied so far, while a copy runs; null when not reported.",
            "title": "Progress Gb"
          },
          "repo": {
            "description": "The model's Hugging Face repo id as it was when the run started; `gateway` for the two gateway actions.",
            "title": "Repo",
            "type": "string"
          },
          "started_at": {
            "description": "When the run was recorded (dispatched).",
            "format": "date-time",
            "title": "Started At",
            "type": "string"
          },
          "status": {
            "description": "`pending`, `running`, `success`, `failed` or `timeout`.",
            "title": "Status",
            "type": "string"
          },
          "triggered_by": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the user (a person or a service account) who started the run; null when not recorded.",
            "title": "Triggered By"
          }
        },
        "required": [
          "id",
          "operation_id",
          "repo",
          "action",
          "status",
          "dispatch_mode",
          "started_at",
          "job_started_at"
        ],
        "title": "StoreRun",
        "type": "object"
      },
      "Tenant": {
        "description": "A tenant of a customer: the unit projects, memberships and AI gateway keys\nbelong to.",
        "properties": {
          "created_at": {
            "description": "When the tenant was registered.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The owning customer's id. Null only for a legacy tenant that no customer owns; such a tenant can be read but never created through v1, where customer_id is required.",
            "title": "Customer Id"
          },
          "default_router_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the tenant's default router; null when none is set.",
            "title": "Default Router Id"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters.",
            "title": "Description"
          },
          "id": {
            "description": "The tenant's id (a UUID).",
            "title": "Id",
            "type": "string"
          },
          "is_primary": {
            "description": "The customer's primary tenant; it can never be deleted.",
            "title": "Is Primary",
            "type": "boolean"
          },
          "member_count": {
            "description": "Its members.",
            "title": "Member Count",
            "type": "integer"
          },
          "name": {
            "description": "The tenant's display name.",
            "title": "Name",
            "type": "string"
          },
          "project_count": {
            "description": "Its projects, retired ones included.",
            "title": "Project Count",
            "type": "integer"
          },
          "slug": {
            "description": "The tenant's short name: lowercase letters, digits and `-`, starting with a letter. Frozen.",
            "title": "Slug",
            "type": "string"
          },
          "updated_at": {
            "description": "The last change; equal to `created_at` until the tenant is first changed, so it is never null.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          }
        },
        "required": [
          "id",
          "customer_id",
          "slug",
          "name",
          "is_primary",
          "project_count",
          "member_count",
          "created_at",
          "updated_at"
        ],
        "title": "Tenant",
        "type": "object"
      },
      "TenantCreate": {
        "additionalProperties": false,
        "description": "A further tenant of an existing customer.",
        "properties": {
          "customer_id": {
            "description": "The customer the tenant belongs to. Frozen after create.",
            "pattern": "^[1-9][0-9]{0,8}$",
            "title": "Customer Id",
            "type": "string"
          },
          "default_router_id": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,8}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The id of the tenant's default router; null when none is set.",
            "title": "Default Router Id"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters.",
            "title": "Description"
          },
          "name": {
            "description": "The tenant's display name.",
            "maxLength": 120,
            "minLength": 2,
            "title": "Name",
            "type": "string"
          },
          "slug": {
            "description": "Lowercase letters, digits and '-', starting with a letter, 2-30 characters. Frozen after create.",
            "pattern": "^[a-z][a-z0-9-]{1,29}$",
            "title": "Slug",
            "type": "string"
          }
        },
        "required": [
          "customer_id",
          "name",
          "slug"
        ],
        "title": "TenantCreate",
        "type": "object"
      },
      "TenantPage": {
        "description": "One page of tenants. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/Tenant"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "TenantPage",
        "type": "object"
      },
      "TenantPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. `description` and `default_router_id`\nare nullable; `name` is not.",
        "properties": {
          "customer_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Customer Id"
          },
          "default_router_id": {
            "anyOf": [
              {
                "pattern": "^[1-9][0-9]{0,8}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Default Router Id"
          },
          "description": {
            "anyOf": [
              {
                "maxLength": 2000,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Free text, up to 2000 characters. null clears it.",
            "title": "Description"
          },
          "name": {
            "anyOf": [
              {
                "maxLength": 120,
                "minLength": 2,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The tenant's display name.",
            "title": "Name"
          },
          "slug": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Frozen.",
            "title": "Slug"
          }
        },
        "title": "TenantPatch",
        "type": "object"
      },
      "User": {
        "description": "A person on this platform, or a service account. Never carries a password\nor an SSO or GitLab identifier.",
        "properties": {
          "ad_username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Windows (directory) account name. Create-only: a PATCH may send the current value (nothing changes); any other value is 422 `immutable_field`, whether or not the person has an SSO account yet.",
            "title": "Ad Username"
          },
          "auth_mode": {
            "anyOf": [
              {
                "enum": [
                  "sso",
                  "local",
                  "both"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Which sign-in routes the person may use. Read-only in v1.",
            "title": "Auth Mode"
          },
          "created_at": {
            "description": "When the user was created.",
            "format": "date-time",
            "title": "Created At",
            "type": "string"
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The person's e-mail address and local sign-in name; unique. Stored and returned entirely LOWER-CASED (local part included), surrounding whitespace dropped, and a `Name <address>` form reduced to the address. Compare case-insensitively. Null only on a legacy row that never had one.",
            "title": "Email"
          },
          "first_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Null only on a legacy row created before first/last names existed.",
            "title": "First Name"
          },
          "gitlab_linked": {
            "description": "A GitLab account exists for them.",
            "title": "Gitlab Linked",
            "type": "boolean"
          },
          "id": {
            "description": "The user's id (a UUID).",
            "title": "Id",
            "type": "string"
          },
          "is_active": {
            "description": "False once deactivated (`DELETE`). `PATCH` with `true` re-activates.",
            "title": "Is Active",
            "type": "boolean"
          },
          "is_internal": {
            "description": "ATAILA staff. Read-only in v1.",
            "title": "Is Internal",
            "type": "boolean"
          },
          "kind": {
            "description": "Read-only. `service` accounts are managed on the portal's service accounts page; every write on one here is a 409.",
            "enum": [
              "human",
              "service"
            ],
            "title": "Kind",
            "type": "string"
          },
          "last_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Null when the person has none.",
            "title": "Last Name"
          },
          "locale": {
            "description": "The language the portal and its e-mails use for the person: `en` or `hu`.",
            "enum": [
              "en",
              "hu"
            ],
            "title": "Locale",
            "type": "string"
          },
          "name": {
            "description": "`first_name` and `last_name` joined; read-only.",
            "title": "Name",
            "type": "string"
          },
          "needs_git_access": {
            "description": "Whether the person is meant to have a GitLab account.",
            "title": "Needs Git Access",
            "type": "boolean"
          },
          "provisioning_status": {
            "anyOf": [
              {
                "enum": [
                  "running",
                  "ok",
                  "partial",
                  "error"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The outcome of the newest provisioning run (username, SSO account, GitLab account, GitLab group): `ok`; `partial` when a step was skipped (typically no GitLab account wanted, or no SSO configured on this platform at all: warning `sso_not_configured` on the create); `error` when a step failed, including a configured SSO that failed. Null when the person was never provisioned.",
            "title": "Provisioning Status"
          },
          "roles": {
            "description": "Every role the person holds, sorted.",
            "items": {
              "type": "string"
            },
            "title": "Roles",
            "type": "array"
          },
          "sso_linked": {
            "description": "An SSO account exists for them.",
            "title": "Sso Linked",
            "type": "boolean"
          },
          "sso_sync_status": {
            "description": "The last SSO projection of this person: `unlinked` (no SSO account), `pending`, `ok` or `error`. Writes through v1 converge the SSO account before answering; the portal also re-converges every 900 s.",
            "enum": [
              "unlinked",
              "pending",
              "ok",
              "error"
            ],
            "title": "Sso Sync Status",
            "type": "string"
          },
          "updated_at": {
            "description": "The last change; equal to `created_at` until the first change.",
            "format": "date-time",
            "title": "Updated At",
            "type": "string"
          },
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The sign-in handle and directory account name. Set at create (derived from the name when omitted). Create-only: a PATCH may send the current value (nothing changes); any other value is 422 `immutable_field`, whether or not the person has an SSO account yet.",
            "title": "Username"
          },
          "warnings": {
            "description": "What did not go as planned on this request, which still succeeded; empty when everything did. Show these to a person.",
            "items": {
              "$ref": "#/components/schemas/ApiWarning"
            },
            "title": "Warnings",
            "type": "array"
          }
        },
        "required": [
          "id",
          "email",
          "username",
          "first_name",
          "name",
          "locale",
          "kind",
          "is_active",
          "is_internal",
          "auth_mode",
          "ad_username",
          "needs_git_access",
          "roles",
          "sso_linked",
          "gitlab_linked",
          "sso_sync_status",
          "provisioning_status",
          "created_at",
          "updated_at"
        ],
        "title": "User",
        "type": "object"
      },
      "UserCreate": {
        "additionalProperties": false,
        "description": "No password: a person created through the API cannot sign in until an\noperator resets their password or they reset it themselves.",
        "properties": {
          "ad_username": {
            "anyOf": [
              {
                "pattern": "^[a-z0-9._-]{1,20}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The Windows account name, when `firstname.lastname` is too long. Lower-case letters, digits, '.', '_' and '-', 1-20 characters, not ending in '.'. Create-only.",
            "title": "Ad Username"
          },
          "email": {
            "description": "The person's e-mail address and local sign-in name; unique. Stored and returned entirely LOWER-CASED (local part included), surrounding whitespace dropped, and a `Name <address>` form reduced to the address. Compare case-insensitively.",
            "format": "email",
            "title": "Email",
            "type": "string"
          },
          "first_name": {
            "description": "The person's first name.",
            "maxLength": 100,
            "minLength": 1,
            "title": "First Name",
            "type": "string"
          },
          "last_name": {
            "anyOf": [
              {
                "maxLength": 100,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The person's last name; may be omitted.",
            "title": "Last Name"
          },
          "locale": {
            "default": "hu",
            "description": "The language the portal and its e-mails use for the person: `en` or `hu`. Default `hu`.",
            "enum": [
              "en",
              "hu"
            ],
            "title": "Locale",
            "type": "string"
          },
          "needs_git_access": {
            "default": false,
            "description": "Create their GitLab account now (and later whenever it is switched on).",
            "title": "Needs Git Access",
            "type": "boolean"
          },
          "username": {
            "anyOf": [
              {
                "pattern": "^[a-z0-9._-]{1,20}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Lower-case letters, digits, '.', '_' and '-', 1-20 characters, not ending in '.'. Omit to derive `firstname.lastname`, folded to ASCII (or `ad_username` when given). Create-only.",
            "title": "Username"
          }
        },
        "required": [
          "email",
          "first_name"
        ],
        "title": "UserCreate",
        "type": "object"
      },
      "UserPage": {
        "description": "One page of users. `next_cursor` reads the next page.",
        "properties": {
          "items": {
            "description": "This page's items, in the list's order.",
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "title": "Items",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Send it as `cursor` to read the next page; null on the last page. Opaque: never build or change one.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "items"
        ],
        "title": "UserPage",
        "type": "object"
      },
      "UserPatch": {
        "additionalProperties": false,
        "description": "JSON Merge Patch (RFC 7396): a member that is omitted keeps its\ncurrent value; a member sent as `null` clears the field when the field is\nnullable (the schema marks it so), and `null` for any other field is a\n422. A `\"\"` is a value (an empty string), not a clear. Only `last_name` is nullable.",
        "properties": {
          "ad_username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Create-only: a PATCH may send the current value (nothing changes); any other value is 422 `immutable_field`, whether or not the person has an SSO account yet.",
            "title": "Ad Username"
          },
          "email": {
            "anyOf": [
              {
                "format": "email",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The person's e-mail address and local sign-in name; unique. Stored and returned entirely LOWER-CASED (local part included), surrounding whitespace dropped, and a `Name <address>` form reduced to the address. Compare case-insensitively. A change answers with a `email_keyed_grants_affected` warning.",
            "title": "Email"
          },
          "first_name": {
            "anyOf": [
              {
                "maxLength": 100,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The person's first name.",
            "title": "First Name"
          },
          "is_active": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "`false` deactivates exactly like `DELETE` (same refusals, same destroy gate); `true` re-activates.",
            "title": "Is Active"
          },
          "last_name": {
            "anyOf": [
              {
                "maxLength": 100,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "null clears it.",
            "title": "Last Name"
          },
          "locale": {
            "anyOf": [
              {
                "enum": [
                  "en",
                  "hu"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "The language the portal and its e-mails use for the person: `en` or `hu`.",
            "title": "Locale"
          },
          "needs_git_access": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "description": "Switching it on creates the GitLab account now. Switching it off does not remove one.",
            "title": "Needs Git Access"
          },
          "username": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Create-only: a PATCH may send the current value (nothing changes); any other value is 422 `immutable_field`, whether or not the person has an SSO account yet.",
            "title": "Username"
          }
        },
        "title": "UserPatch",
        "type": "object"
      },
      "Whoami": {
        "description": "Who is calling, how, and what they may do right now.",
        "properties": {
          "auth_kind": {
            "description": "How the caller authenticated: `session` (signed in to the portal), `pat` (a personal API token) or `service_account` (a service-account token). Other values may appear.",
            "title": "Auth Kind",
            "type": "string"
          },
          "expires_at": {
            "anyOf": [
              {
                "format": "date-time",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "When the credential stops working: the token's expiry, or the session's.",
            "title": "Expires At"
          },
          "principal": {
            "$ref": "#/components/schemas/WhoamiPrincipal",
            "description": "The calling account."
          },
          "scopes": {
            "description": "The permission keys in effect for this request, sorted. For a token, its scopes that its owner still holds; for a portal session, the account's roles.",
            "items": {
              "type": "string"
            },
            "title": "Scopes",
            "type": "array"
          },
          "token": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/WhoamiToken"
              },
              {
                "type": "null"
              }
            ],
            "description": "The token, when the credential is one; null for a portal session."
          }
        },
        "required": [
          "principal",
          "auth_kind",
          "scopes"
        ],
        "title": "Whoami",
        "type": "object"
      },
      "WhoamiPrincipal": {
        "description": "The account behind the credential.",
        "properties": {
          "email": {
            "description": "The account's e-mail address; a service account's is a synthetic address that receives no mail.",
            "title": "Email",
            "type": "string"
          },
          "id": {
            "description": "The account's user id.",
            "title": "Id",
            "type": "string"
          },
          "kind": {
            "description": "`human` (a person) or `service` (a service account). Other values may appear.",
            "title": "Kind",
            "type": "string"
          },
          "name": {
            "description": "The account's display name.",
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "id",
          "email",
          "name",
          "kind"
        ],
        "title": "WhoamiPrincipal",
        "type": "object"
      },
      "WhoamiToken": {
        "description": "The API token this request was made with.",
        "properties": {
          "allow_destroy": {
            "description": "The token may archive, delete, deactivate and retire; without it those operations answer 403 `destroy_not_allowed`.",
            "title": "Allow Destroy",
            "type": "boolean"
          },
          "granted_scopes": {
            "description": "The scopes the token was created with. What it may do now is `scopes` on the answer: these, less any its owner no longer holds.",
            "items": {
              "type": "string"
            },
            "title": "Granted Scopes",
            "type": "array"
          },
          "id": {
            "description": "The token's id, as the audit log records it (`token_id`).",
            "title": "Id",
            "type": "string"
          },
          "name": {
            "description": "The name the token was given when it was created.",
            "title": "Name",
            "type": "string"
          },
          "prefix": {
            "description": "The token's public prefix, which the portal shows to tell tokens apart. Never the secret part.",
            "title": "Prefix",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "granted_scopes",
          "allow_destroy"
        ],
        "title": "WhoamiToken",
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "bearerFormat": "ataila_pat_… | ataila_sat_…",
        "description": "An ATAILA API token (personal `ataila_pat_…` or service account `ataila_sat_…`). A portal session JWT is accepted as well.",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "The versioned API of the ATAILA Cloud Platform. Authenticate with `Authorization: Bearer <token>` using a personal (`ataila_pat_…`) or service-account (`ataila_sat_…`) API token. Errors are RFC 9457 problem details (`application/problem+json`) with a stable `code` (Errors, below). Timestamps are RFC 3339 in UTC. Every POST that creates or starts something (all of them except `POST /mcp`, which only reads) and the node-cache `PUT` and `DELETE` accept an `Idempotency-Key` header, declared on each: for 24 hours the same key with the same request replays the stored response (`Idempotent-Replayed: true`), with a different request it is a 409 `idempotency_key_reused`, and while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. PATCH bodies are JSON Merge Patch (RFC 7396). Limit: 600 requests per minute per token (429 `rate_limited` with `Retry-After`). Every response carries `X-Request-ID`.\n\n**Treat every API token as an operator credential.** A token is a remote handle on this portal, and the portal holds the credentials the platform itself runs on: whoever holds a token can do, through this API, everything its scopes allow on this installation. Give each token one purpose, only the scopes that purpose needs and the shortest lifetime that works; keep it in a secret store or a protected CI variable, never in a repository or a configuration file; create it with `allow_destroy` only when it is meant to remove things; and revoke it when its job is done.\n\n**Errors.** Every error is a problem document with these members: `type`, `urn:ataila:api:problem:<code>`, an identifier rather than a link; `title`, the HTTP status phrase; `status`, the HTTP status again; `detail`, what went wrong this time, for a person, worded freely; `code`, the stable reason to branch on; `instance`, the request path; and `request_id`, the same as the `X-Request-ID` header. Some codes add members, named below; ignore any member you do not know. Each operation names its own codes in its responses. These come from the layers every request passes through, so any operation can answer them:\n\n* 401 `not_authenticated`: no `Authorization` header, or not `Bearer <token>`. 401 `token_invalid`: the token is malformed or unknown, or a session token does not verify (an expired one included). 401 `token_expired` and `token_revoked`: the API token has expired or was revoked. 401 `principal_disabled`: the account behind the token or session is deactivated. 401 `token_ip_not_allowed`: the token's address allowlist does not include the caller. A 401 carries `WWW-Authenticate: Bearer`; retrying with the same credential does not help.\n* 403 `forbidden`: the operation needs a permission the caller lacks; `required` lists the permission keys, any one of which would do. A token holds only those of its scopes its owner still holds. 403 `destroy_not_allowed`: a destroy (archive, delete, deactivate, retire) with a token created without `allow_destroy`.\n* 403 `licence_locked`: the licence has expired or was revoked, so every change is refused except installing a licence (`PUT /licence/bundle`). 403 `licence_restricted`: this platform is not licensed yet, so nothing that grows it (customers, tenants, projects, releases, AI) can be added or changed. 403 `licence_required`: the licence lacks a module the operation needs, named in `entitlement`. 403 `licence_refused`: any other licence refusal. Each carries `state` (the licence state), `state_reason`, `remedy` (what an operator must do) and `remedy_url`. A read is never refused for a licence reason. Never retry a `licence_*` code: only a licence change alters the answer.\n* 400 `invalid_idempotency_key`: the `Idempotency-Key` is not 1-255 printable characters. 409 `idempotency_key_reused`: the key was used for a different request (method, path, query or body) in the last 24 hours. 429 `idempotency_request_in_progress`: the first request with the key is still running.\n* 400 `invalid_cursor`: the `cursor` is not one this list issued.\n* 422 `validation_failed`: the request does not match the schema; `errors` lists each failure (`loc`, `msg`, `type`) and `field` names the first offending member. 422 `immutable_field`: a change to a field that is frozen once created; `field` names it.\n* 429 `rate_limited`: more than 600 requests in a minute with this token.\n* 503 `unavailable`: the platform cannot answer right now. 503 `api_tokens_unconfigured`: API tokens are not configured on this platform; an operator must act, and retrying does not help.\n* 404 `not_found`: every path, this document and the interactive reference included, while the public API is switched off on this platform; and any path that does not exist. 405 `method_not_allowed`: the path exists, the method does not. 500 `internal_error`: an unexpected failure, with no detail; `request_id` finds it in the server log.\n\nA 429 and a 503 carry `Retry-After` (seconds) when a retry can succeed: wait that long, then send the same request again. When no specific code applies, `code` is the one for the status: `bad_request` (400), `not_authenticated` (401), `forbidden` (403), `not_found` (404), `method_not_allowed` (405), `conflict` (409), `gone` (410), `precondition_failed` (412), `unsupported_media_type` (415), `validation_failed` (422), `rate_limited` (429), `internal_error` (500), `bad_gateway` (502), `unavailable` (503) and `gateway_timeout` (504).",
    "title": "ATAILA Cloud Platform API",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/ai-models": {
      "get": {
        "description": "The model catalogue, in `id` order: every model the platform records, whether or not\nits weights are present. The filters are exact and combine: `repo` finds the row of\none Hugging Face repo (the `id` an import needs); `status`, `category` and\n`gateway_tier` narrow the list.",
        "operationId": "ai_models_list",
        "parameters": [
          {
            "description": "Exact repo id: finds a model's `id` to import it.",
            "in": "query",
            "name": "repo",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact repo id: finds a model's `id` to import it.",
              "title": "Repo"
            }
          },
          {
            "description": "Exact status.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 20,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact status.",
              "title": "Status"
            }
          },
          {
            "in": "query",
            "name": "category",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 24,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Category"
            }
          },
          {
            "in": "query",
            "name": "gateway_tier",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 40,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Gateway Tier"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiModelPage"
                }
              }
            },
            "description": "One page of the catalogue.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List AI models",
        "tags": [
          "ai-models"
        ]
      },
      "post": {
        "description": "Records a catalogue row. The model starts `planned`, with no central copy and no node cache: weights arrive only through the store actions, and pulling them is not part of v1. `status`, `location`, `offline_ready` and `nas_volume` are not accepted. Send an `Idempotency-Key` to make a retry safe: a retry with the same key and request gets the first answer and changes nothing.",
        "operationId": "ai_models_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiModelCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiModel"
                }
              }
            },
            "description": "The model, as recorded.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The repo is already in the catalogue (`repo_taken`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The repo is not a strict Hugging Face id, or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Add an AI model to the catalogue",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/load-targets": {
      "get": {
        "description": "The nodes and DGX clusters a model can be served on, with their VRAM budget. Live values when monitoring answers, static fallbacks otherwise.",
        "operationId": "ai_models_load_targets_list",
        "parameters": [
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoadTargetPage"
                }
              }
            },
            "description": "One page of load targets.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List load targets",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/runs/{run_id}": {
      "get": {
        "description": "One run of the model store, as recorded: a node cache or uncache started through\nthis API, or a run started in the portal. The same run is the operation\n`model-store-run:<id>`; `GET /operations/{id}` reports it in the shape every\nlong-running operation shares.",
        "operationId": "ai_models_runs_get",
        "parameters": [
          {
            "description": "The run's id.",
            "in": "path",
            "name": "run_id",
            "required": true,
            "schema": {
              "description": "The run's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Run Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreRun"
                }
              }
            },
            "description": "The store run.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such run (`run_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One store run",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/storage": {
      "get": {
        "description": "The central-store shares and each node's local disk with the models cached on it, as last scanned. Nothing is scanned by this read.",
        "operationId": "ai_models_storage_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Storage"
                }
              }
            },
            "description": "The storage, as last scanned.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Model storage",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/{model_id}": {
      "delete": {
        "description": "Removes the catalogue ROW and nothing else: no disk is touched. It is refused while the row is the record of weights that exist (a central copy, or `status` `owned` / `serving`), while any node holds a cache, and while a store run is pending or running. Removing a node cache first is allowed (`DELETE .../node-caches/{node}`); removing a central copy is not possible through v1. Needs the admin permission; NOT destroy-gated, because it never destroys weights.",
        "operationId": "ai_models_delete",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The catalogue row was removed.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The model still has weights or work: an active store run (`model_has_active_run`), a node cache (`model_has_node_caches`) or a central copy (`model_has_central_copy`). `blockers` counts each: `{\"active_runs\": n, \"node_caches\": n, \"central_copy\": 1}`.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Remove an AI model from the catalogue",
        "tags": [
          "ai-models"
        ]
      },
      "get": {
        "description": "One model of the catalogue, by `id`, as recorded. This read contacts no node and\nscans no storage.",
        "operationId": "ai_models_get",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiModel"
                }
              }
            },
            "description": "The model.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One AI model",
        "tags": [
          "ai-models"
        ]
      },
      "patch": {
        "description": "Metadata only. `repo` is frozen; `status`, `location`, `offline_ready` and `nas_volume` are read-only (set by the store actions): each may be sent with its current value, and a different value is a 422.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "ai_models_update",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiModelPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/AiModelPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiModel"
                }
              }
            },
            "description": "The model after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`repo` was changed (`immutable_field`), a read-only field was changed (`read_only_field`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change an AI model's metadata",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/{model_id}/node-caches": {
      "get": {
        "description": "The model's node-cache records, in `node` order: one per node that holds, held or is\ngetting a local copy; `state` says which (`cached` once the copy is complete). Empty\nwhen no node ever cached the model; 404 when the model does not exist.",
        "operationId": "ai_models_node_caches_list",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NodeCachePage"
                }
              }
            },
            "description": "One page of the model's node caches.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List a model's node caches",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai-models/{model_id}/node-caches/{node}": {
      "delete": {
        "description": "Deletes the node's local copy (recoverable: the central copy is untouched) and answers 202 with operation `model-store-run:<id>`. Refused while the model is loaded on that node, and — because that cannot be proven otherwise — while monitoring cannot be read.\n\nThe run is dispatched to the runner and followed by the portal, which survives an API restart; its time budget starts when the runner job starts, not while it queues. On an estate that fakes dispatch (sandbox, or dispatch mode `dryrun` or `simulate`) the operation says `dispatch_mode: dryrun`: the run holds a fake pipeline id, nothing reaches the runner and nothing is simulated — a store run is never simulated, so under `simulate` it behaves exactly as under `dryrun` and the operation ends `failed`. Poll `GET /operations/{id}` (also the `Location` header) until `succeeded` or `failed`. `Idempotency-Key` is honoured: a retry with the same key and request gets the same answer.",
        "operationId": "ai_models_node_caches_delete",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          },
          {
            "description": "The AI node's hostname, e.g. `prod-ai-03`.",
            "in": "path",
            "name": "node",
            "required": true,
            "schema": {
              "description": "The AI node's hostname, e.g. `prod-ai-03`.",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$",
              "title": "Node",
              "type": "string"
            }
          },
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            },
            "description": "The removal started: poll the operation.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The `Idempotency-Key` is not 1-255 printable characters (`invalid_idempotency_key`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`), or no cache of it on that node (`node_cache_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A store run of this model is pending or running (`run_in_progress`; `operation_id` names it), the key was used for another request (`idempotency_key_reused`), or — cache — the model has no central copy to cache from (`no_central_copy`), or — uncache — it is loaded on the node (`model_loaded_on_node`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The node is not an AI node (`unknown_node`) or has no management address (`node_has_no_mgmt_ip`), the stored repo is not a strict Hugging Face id (`unsafe_repo`), or the model's share is not a current one (`unknown_volume`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The runner pipeline could not be triggered (`dispatch_failed`; the run is recorded as failed and `operation_id` names it).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Whether the model is loaded on the node cannot be read right now (`loaded_state_unknown`); nothing was dispatched. Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Remove a model's cache from a node",
        "tags": [
          "ai-models"
        ]
      },
      "get": {
        "description": "The model's cache on one node. A record whose copy was removed (`state` `absent`)\nanswers 404, like a node that never had one.",
        "operationId": "ai_models_node_caches_get",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          },
          {
            "description": "The AI node's hostname, e.g. `prod-ai-03`.",
            "in": "path",
            "name": "node",
            "required": true,
            "schema": {
              "description": "The AI node's hostname, e.g. `prod-ai-03`.",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$",
              "title": "Node",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NodeCache"
                }
              }
            },
            "description": "The node cache.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`) or no cache of it on that node (`node_cache_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One node cache",
        "tags": [
          "ai-models"
        ]
      },
      "put": {
        "description": "Copies the model from the central store to the node's local disk (a fast, offline-ready serving copy) and answers 202 with operation `model-store-run:<id>`. The model must have a central copy. When the node already holds a cached copy the answer is 200 with the cache and nothing is dispatched.\n\nThe run is dispatched to the runner and followed by the portal, which survives an API restart; its time budget starts when the runner job starts, not while it queues. On an estate that fakes dispatch (sandbox, or dispatch mode `dryrun` or `simulate`) the operation says `dispatch_mode: dryrun`: the run holds a fake pipeline id, nothing reaches the runner and nothing is simulated — a store run is never simulated, so under `simulate` it behaves exactly as under `dryrun` and the operation ends `failed`. Poll `GET /operations/{id}` (also the `Location` header) until `succeeded` or `failed`. `Idempotency-Key` is honoured: a retry with the same key and request gets the same answer.",
        "operationId": "ai_models_node_caches_put",
        "parameters": [
          {
            "description": "The model's id (`id` on a model).",
            "in": "path",
            "name": "model_id",
            "required": true,
            "schema": {
              "description": "The model's id (`id` on a model).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Model Id",
              "type": "string"
            }
          },
          {
            "description": "The AI node's hostname, e.g. `prod-ai-03`.",
            "in": "path",
            "name": "node",
            "required": true,
            "schema": {
              "description": "The AI node's hostname, e.g. `prod-ai-03`.",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,79}$",
              "title": "Node",
              "type": "string"
            }
          },
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NodeCache"
                }
              }
            },
            "description": "The node already holds a cached copy; nothing was dispatched.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            },
            "description": "The copy started: poll the operation.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The `Idempotency-Key` is not 1-255 printable characters (`invalid_idempotency_key`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such model (`model_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A store run of this model is pending or running (`run_in_progress`; `operation_id` names it), the key was used for another request (`idempotency_key_reused`), or — cache — the model has no central copy to cache from (`no_central_copy`), or — uncache — it is loaded on the node (`model_loaded_on_node`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The node is not an AI node (`unknown_node`) or has no management address (`node_has_no_mgmt_ip`), the stored repo is not a strict Hugging Face id (`unsafe_repo`), or the model's share is not a current one (`unknown_volume`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The runner pipeline could not be triggered (`dispatch_failed`; the run is recorded as failed and `operation_id` names it).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Cache a model on a node",
        "tags": [
          "ai-models"
        ]
      }
    },
    "/ai/catalog": {
      "get": {
        "description": "The launchable models per node: key, host, label, model, engine, port and enabled. The load and unload commands are never returned.",
        "operationId": "ai_catalog_list",
        "parameters": [
          {
            "description": "Exact host.",
            "in": "query",
            "name": "host",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 80,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact host.",
              "title": "Host"
            }
          },
          {
            "in": "query",
            "name": "enabled",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Enabled"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LaunchCatalogPage"
                }
              }
            },
            "description": "One page of the launch catalogue.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List the launch catalogue",
        "tags": [
          "ai-nodes"
        ]
      }
    },
    "/ai/clusters": {
      "get": {
        "description": "The DGX clusters as recorded. A read: it does not converge a cluster that is forming or breaking.",
        "operationId": "ai_clusters_list",
        "parameters": [
          {
            "description": "Exact name: finds a cluster to import.",
            "in": "query",
            "name": "name",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 40,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact name: finds a cluster to import.",
              "title": "Name"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DgxClusterPage"
                }
              }
            },
            "description": "One page of DGX clusters.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List DGX clusters",
        "tags": [
          "ai-nodes"
        ]
      }
    },
    "/ai/gateway": {
      "get": {
        "description": "The OpenAI-compatible base URL and the serving-tier names. The base URL\ncomes from the gateway credential the keys are minted against, so it always\nnames the gateway that issued them.",
        "operationId": "ai_gateway_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiGateway"
                }
              }
            },
            "description": "The AI gateway.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The AI gateway",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/gateway/keys": {
      "get": {
        "description": "Registry data only (`live` is `not_read`): the list does not call the gateway and works when it is down. Read one key for its live allowlist, limits and spend.",
        "operationId": "ai_gateway_keys_list",
        "parameters": [
          {
            "description": "Only this tenant's keys.",
            "in": "query",
            "name": "organization_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only this tenant's keys.",
              "title": "Organization Id"
            }
          },
          {
            "in": "query",
            "name": "env",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "dev",
                    "uat",
                    "prod"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env"
            }
          },
          {
            "description": "Exact app.",
            "in": "query",
            "name": "app",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact app.",
              "title": "App"
            }
          },
          {
            "in": "query",
            "name": "origin",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "api",
                    "adopted"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Origin"
            }
          },
          {
            "description": "Exact alias: at most one live key. Finds the `id` to import a key by its name.",
            "in": "query",
            "name": "key_alias",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact alias: at most one live key. Finds the `id` to import a key by its name.",
              "title": "Key Alias"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKeyPage"
                }
              }
            },
            "description": "One page of virtual keys.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List virtual keys",
        "tags": [
          "ai-gateway"
        ]
      },
      "post": {
        "description": "Mints a key named `<tenant-slug>-<env>-<app>[-<feature>]` and stores its value in the secrets store at `secret_path` (always). The value is in this response only when `expose_secret` is true; an idempotent replay never carries it. Budgets are soft: the gateway alerts and never blocks. The answer shows what was written (`live` is `not_read`, `spend_usd` null): GET the key for its live values. Send an `Idempotency-Key` to make a retry safe: a retry with the same key and request gets the first answer and changes nothing.",
        "operationId": "ai_gateway_keys_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayKeyCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKey"
                }
              }
            },
            "description": "The key, as written.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A live key has the alias (`key_alias_taken`), or the gateway already has a key with it that is not registered (`key_alias_on_gateway`: adopt it instead).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`organization_not_found`) or project (`project_not_found`, `project_not_in_organization`), a tier the catalogue does not have (`unknown_tier`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway refused the call (`gateway_refused`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Checked BEFORE the tenant, project and tiers the body names, so a platform without a gateway answers 503 whatever the body says. Or the secrets store did not keep the value (`secret_store_write_failed`); the key was then removed from the gateway again (`key_removed_from_gateway`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create a virtual key",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/gateway/keys/{key_id}": {
      "delete": {
        "description": "Deletes the key in the gateway — IRREVERSIBLY: every client using it fails at once — then the secrets store entry and pointer the portal wrote for it (an adopted key's secrets store entry belongs to its consumer and is left alone), and marks the registry row deleted. Needs the admin permission; NOT destroy-gated (a token without `allow_destroy` may delete keys). A key the gateway had already lost is deleted from the registry the same way.",
        "operationId": "ai_gateway_keys_delete",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The key was deleted.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such key (`key_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway refused the call (`gateway_refused`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Delete a virtual key",
        "tags": [
          "ai-gateway"
        ]
      },
      "get": {
        "description": "The registry row with the key's LIVE allowlist, limits and spend from the gateway. `live` is `missing` when the gateway no longer has the key. Never the key's value.",
        "operationId": "ai_gateway_keys_get",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKey"
                }
              }
            },
            "description": "The key, with its live values.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such key (`key_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One virtual key",
        "tags": [
          "ai-gateway"
        ]
      },
      "patch": {
        "description": "Changes the allowlist, the limits and the soft budget on the gateway without changing the key's value (that is a rotation). `organization_id`, `env`, `app` and `feature` are frozen: sending the current value is accepted, a different one is a 422. Changing only `project_id` does not call the gateway. The answer shows what was written (`live` is `not_read`, `spend_usd` null): GET the key for its live values.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "ai_gateway_keys_update",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayKeyPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayKeyPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKey"
                }
              }
            },
            "description": "The key after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such key (`key_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway no longer has the key (`key_missing_on_gateway`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A frozen key was changed (`immutable_field`), an unknown tier (`unknown_tier`), no such project (`project_not_found`, `project_not_in_organization`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway refused the call (`gateway_refused`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a virtual key",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/gateway/keys/{key_id}/rotations": {
      "post": {
        "description": "A new value under the same alias, with the key's current allowlist, limits and soft budget. The new value is stored in the secrets store at `secret_path` and is in this response only when `expose_secret` is true. The old value stops working at once. The answer shows registry values (`live` is `not_read`, `spend_usd` null): GET the key for its live values. Send an `Idempotency-Key` to make a retry safe: a retry with the same key and request gets the first answer and changes nothing.",
        "operationId": "ai_gateway_keys_rotate",
        "parameters": [
          {
            "in": "path",
            "name": "key_id",
            "required": true,
            "schema": {
              "title": "Key Id",
              "type": "string"
            }
          },
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GatewayKeyRotation"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GatewayKey"
                }
              }
            },
            "description": "The key with its new value.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such key (`key_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The key was adopted (`key_adopted`: its value lives in a consumer's own secrets store entry, so a new value would break that consumer), or the gateway no longer has it (`key_missing_on_gateway`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "502": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway refused the call (`gateway_refused`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The gateway is not configured on this platform (`gateway_not_configured`) or cannot be reached (`gateway_unreachable`). Or the secrets store did not keep the new value (`secret_store_write_failed`); the key then keeps its old value. Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Rotate a virtual key",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/gateway/tiers": {
      "get": {
        "description": "The serving tiers of the AI gateway, in `key` order, each with what serves it right\nnow (`resolved_model`, `source`) and the models it could be pinned to\n(`candidate_models`). Tiers exist only as the platform defines them: this API pins\nand enables a tier (`PUT`), it never creates or deletes one.",
        "operationId": "ai_gateway_tiers_list",
        "parameters": [
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServingTierPage"
                }
              }
            },
            "description": "One page of serving tiers.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List serving tiers",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/gateway/tiers/{key}": {
      "get": {
        "description": "One serving tier by `key`, with what serves it right now and the models it could be\npinned to.",
        "operationId": "ai_gateway_tiers_get",
        "parameters": [
          {
            "description": "The tier's name, e.g. `code-max`.",
            "in": "path",
            "name": "key",
            "required": true,
            "schema": {
              "description": "The tier's name, e.g. `code-max`.",
              "title": "Key",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServingTier"
                }
              }
            },
            "description": "The serving tier.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tier (`tier_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One serving tier",
        "tags": [
          "ai-gateway"
        ]
      },
      "put": {
        "description": "Sets `pinned_model` and/or `enabled` on an existing tier; an omitted member is left unchanged, `pinned_model: null` returns the tier to auto-assign. The gateway is then reconciled at once (a `reconcile_not_applied` warning says when it could not be reached; the periodic reconcile applies the change later). A pin changes what EVERY client of the tier gets. Destroying a tier in Terraform only forgets it: there is no delete.",
        "operationId": "ai_gateway_tiers_put",
        "parameters": [
          {
            "description": "The tier's name, e.g. `code-max`.",
            "in": "path",
            "name": "key",
            "required": true,
            "schema": {
              "description": "The tier's name, e.g. `code-max`.",
              "title": "Key",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServingTierPut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServingTier"
                }
              }
            },
            "description": "The serving tier after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tier (`tier_not_found`). Tiers exist only by migration: there is no create or delete.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`pinned_model` is not loaded on the fleet (`model_not_loaded`; `candidates` lists what is) and `allow_unloaded_pin` was not set, or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Pin or enable a serving tier",
        "tags": [
          "ai-gateway"
        ]
      }
    },
    "/ai/nodes": {
      "get": {
        "description": "The AI fleet. Roster fields are always present; live fields are null when monitoring cannot be read (`monitoring_reachable: false`). Never 503.",
        "operationId": "ai_nodes_list",
        "parameters": [
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiNodePage"
                }
              }
            },
            "description": "One page of AI nodes.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List AI nodes",
        "tags": [
          "ai-nodes"
        ]
      }
    },
    "/ai/nodes/{hostname}": {
      "get": {
        "description": "One node, as in the list. Never 503.",
        "operationId": "ai_nodes_get",
        "parameters": [
          {
            "description": "The node's hostname, e.g. `prod-ai-03`.",
            "in": "path",
            "name": "hostname",
            "required": true,
            "schema": {
              "description": "The node's hostname, e.g. `prod-ai-03`.",
              "title": "Hostname",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiNode"
                }
              }
            },
            "description": "The AI node.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not an AI node (`node_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One AI node",
        "tags": [
          "ai-nodes"
        ]
      }
    },
    "/audit-events": {
      "get": {
        "description": "Every recorded change on this platform, newest first (`occurred_at`, then `id`, descending). Pages are cursor-based and stable while new events are written: pass `next_cursor` as `cursor` to get the next page; it is null on the last one. A cursor that is not one of this list's is a 400 `invalid_cursor`.\n\nFilters combine with AND, and every one is exact unless stated: `actor` (an e-mail address or other actor string, compared lower-cased; or a user id, which matches the events recorded under that person's CURRENT address — events recorded under an earlier address need that address), `auth_kind`, `token_id`, `request_id`, `entity_type`, `entity_id`, `action` (exact, or a PREFIX when it ends in `*`: `user.*` matches `user.create` and `user.role_grant`; `*` alone matches every action), `occurred_from` (inclusive) and `occurred_to` (EXCLUSIVE). A range whose end is not after its start is simply empty.\n\n`before_state` and `after_state` are returned as the writer recorded them, except that every member whose name looks secret is null. For `entity_type` `licence` the `entity_id` is the licence serial, masked to its last group unless the caller holds `licence-admin-global`, as on `GET /licence`; the `entity_id` filter matches the stored id, never the masked one. Reading the log is not itself audited.",
        "operationId": "audit_events_list",
        "parameters": [
          {
            "description": "Exact actor: an e-mail address (compared lower-cased), `system`, `pipeline:<run id>`…, or a user id (UUID) for that person's events.",
            "in": "query",
            "name": "actor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 320,
                  "minLength": 1,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact actor: an e-mail address (compared lower-cased), `system`, `pipeline:<run id>`…, or a user id (UUID) for that person's events.",
              "title": "Actor"
            }
          },
          {
            "description": "How the actor authenticated.",
            "in": "query",
            "name": "auth_kind",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "session",
                    "pat",
                    "service_account"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "How the actor authenticated.",
              "title": "Auth Kind"
            }
          },
          {
            "description": "Events made with this API token.",
            "in": "query",
            "name": "token_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "uuid",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Events made with this API token.",
              "title": "Token Id"
            }
          },
          {
            "description": "Events of one request (`X-Request-ID`).",
            "in": "query",
            "name": "request_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "minLength": 1,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Events of one request (`X-Request-ID`).",
              "title": "Request Id"
            }
          },
          {
            "description": "Exact entity type, e.g. `users`.",
            "in": "query",
            "name": "entity_type",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "minLength": 1,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact entity type, e.g. `users`.",
              "title": "Entity Type"
            }
          },
          {
            "description": "Exact entity id, as the writer spelled it.",
            "in": "query",
            "name": "entity_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 500,
                  "minLength": 1,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact entity id, as the writer spelled it.",
              "title": "Entity Id"
            }
          },
          {
            "description": "Exact action, or a prefix when it ends in `*` (`user.*`).",
            "in": "query",
            "name": "action",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "maxLength": 200,
                  "minLength": 1,
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact action, or a prefix when it ends in `*` (`user.*`).",
              "title": "Action"
            }
          },
          {
            "description": "Events at or after this time (inclusive). RFC 3339; without an offset, UTC.",
            "in": "query",
            "name": "occurred_from",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date-time",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Events at or after this time (inclusive). RFC 3339; without an offset, UTC.",
              "title": "Occurred From"
            }
          },
          {
            "description": "Events BEFORE this time (exclusive). RFC 3339; without an offset, UTC.",
            "in": "query",
            "name": "occurred_to",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "date-time",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Events BEFORE this time (exclusive). RFC 3339; without an offset, UTC.",
              "title": "Occurred To"
            }
          },
          {
            "description": "Page size (at most 500).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size (at most 500).",
              "maximum": 500,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditEventPage"
                }
              }
            },
            "description": "One page of audit events, newest first.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List audit events",
        "tags": [
          "audit"
        ]
      }
    },
    "/audit-events/{event_id}": {
      "get": {
        "description": "One event by id, with the same secret-looking members withheld and the same licence serial masking as in the list.",
        "operationId": "audit_events_get",
        "parameters": [
          {
            "description": "The event's id.",
            "in": "path",
            "name": "event_id",
            "required": true,
            "schema": {
              "description": "The event's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Event Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditEvent"
                }
              }
            },
            "description": "The audit event.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such event (`audit_event_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One audit event",
        "tags": [
          "audit"
        ]
      }
    },
    "/brand": {
      "get": {
        "description": "The one brand of this platform. `attribution` and `first_party` are read-only and computed. The `ETag` response header carries `version` for `If-Match`. `PUT /brand` is a FULL replacement: to change one field, send back every writable field of this answer, the unchanged ones included. A field left out is refused (422 naming it), and `null` for an asset id clears that asset.",
        "operationId": "brand_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Brand"
                }
              }
            },
            "description": "The brand.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No brand is configured (`brand_not_configured`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "This platform's brand",
        "tags": [
          "brand"
        ]
      },
      "put": {
        "description": "Replaces every v1 field: a FULL replacement, never a partial update. All are required, so a field left out is a 422 naming it and is never reset; the asset ids may be null, which CLEARS the asset. To change one field, read the brand and send every field back. `attribution` and `first_party` cannot be sent (422). The fields v1 does not manage (the sidebar tagline, the sign-in title and subtitle, the footer links) keep their stored values. With `If-Match: \"<version>\"` the replace happens only while the brand is still at that version (412 `version_mismatch` otherwise); without it the last write wins, as in the portal's Brand Center. A replace that changes nothing returns the brand as it is: `version` is not bumped and no audit row is written. The change applies to every tenant and user of this platform, the sign-in page included. There is no delete.",
        "operationId": "brand_put",
        "parameters": [
          {
            "description": "The `version` last read, as an entity tag (`\"7\"`); `*` matches any.",
            "in": "header",
            "name": "If-Match",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "The `version` last read, as an entity tag (`\"7\"`); `*` matches any.",
              "title": "If-Match"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandPut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Brand"
                }
              }
            },
            "description": "The brand after the replace.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`If-Match` is not a version (`invalid_if_match`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No brand is configured (`brand_not_configured`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "412": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`If-Match` names another version (`version_mismatch`); `current_version` is the stored one.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An asset id does not exist (`asset_not_found`) or is the wrong kind (`asset_wrong_kind`), with `field`; or the body is invalid (`validation_failed`, `field` naming the first offending member): a required field left out, or `attribution` / `first_party` sent.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Replace the brand",
        "tags": [
          "brand"
        ]
      }
    },
    "/brand/assets": {
      "get": {
        "description": "The brand assets uploaded to this platform, in `id` order, filtered by `kind` and by\nthe exact `sha256` of a file (to find out whether it is already uploaded). Assets\nare never deleted: one that no brand field names any more is still listed.",
        "operationId": "brand_assets_list",
        "parameters": [
          {
            "in": "query",
            "name": "kind",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "logo",
                    "favicon"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Kind"
            }
          },
          {
            "description": "Exact sha256 (lower-case hex) of the file.",
            "in": "query",
            "name": "sha256",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[0-9a-f]{64}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact sha256 (lower-case hex) of the file.",
              "title": "Sha256"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandAssetPage"
                }
              }
            },
            "description": "One page of brand assets.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List brand assets",
        "tags": [
          "brand"
        ]
      },
      "post": {
        "description": "Accepts `multipart/form-data` with `file` and `kind` (as the portal's Brand Center sends) or `application/json` with `kind` and `content_base64`; both are validated the same way: PNG, WebP or SVG for a logo (120-2000 px wide), PNG, SVG or ICO for a favicon, at most 512 KB, SVG without active content. Assets are content-addressed: uploading bytes that are already stored as the same kind returns that asset with 200 and writes nothing; the same bytes as the other kind are a 409. Everything uploaded is readable WITHOUT signing in at `url` (the sign-in page shows it), so upload nothing that is not public. There is no delete. Send an `Idempotency-Key` to make a retry safe: a retry with the same key and request gets the first answer and changes nothing.",
        "operationId": "brand_assets_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BrandAssetUpload"
              }
            },
            "multipart/form-data": {
              "schema": {
                "properties": {
                  "file": {
                    "format": "binary",
                    "type": "string"
                  },
                  "kind": {
                    "enum": [
                      "logo",
                      "favicon"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "file",
                  "kind"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandAsset"
                }
              }
            },
            "description": "These bytes are already stored as this kind: the existing asset. Nothing new is written (a missing stored object is stored again).",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandAsset"
                }
              }
            },
            "description": "The asset was stored.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An `application/json` body that is not valid JSON (`bad_request`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "These bytes are already stored as the OTHER kind (`asset_kind_conflict`); `existing_asset_id` and `existing_kind` name it.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "415": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Neither `multipart/form-data` nor `application/json` (`unsupported_media_type`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The file is refused (`asset_invalid`: type, size, SVG content, logo width), `content_base64` is not base64, or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Object storage is not configured, so a new asset cannot be stored (`storage_unavailable`). Also: the platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Upload a brand asset",
        "tags": [
          "brand"
        ]
      }
    },
    "/brand/assets/{asset_id}": {
      "get": {
        "description": "One brand asset by `id`. The file itself is at its `url`, readable without signing\nin.",
        "operationId": "brand_assets_get",
        "parameters": [
          {
            "description": "The asset's id (`id` on a brand asset).",
            "in": "path",
            "name": "asset_id",
            "required": true,
            "schema": {
              "description": "The asset's id (`id` on a brand asset).",
              "title": "Asset Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandAsset"
                }
              }
            },
            "description": "The brand asset.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such asset (`brand_asset_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One brand asset",
        "tags": [
          "brand"
        ]
      }
    },
    "/customers": {
      "get": {
        "description": "The customers of this platform, in `id` order, archived ones included. The filters\nare exact and combine: `short_name`, `gitlab_group`, `status`. A list never contacts\nGitLab; read one customer with `include=gitlab_status` for its group's live state.",
        "operationId": "customers_list",
        "parameters": [
          {
            "description": "Exact short name.",
            "in": "query",
            "name": "short_name",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact short name.",
              "title": "Short Name"
            }
          },
          {
            "description": "Exact GitLab group.",
            "in": "query",
            "name": "gitlab_group",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact GitLab group.",
              "title": "Gitlab Group"
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "active",
                    "suspended",
                    "archived"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerPage"
                }
              }
            },
            "description": "One page of customers.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List customers",
        "tags": [
          "customers"
        ]
      },
      "post": {
        "description": "Creates the customer (with `status` `active` unless `suspended` is asked\nfor) and its primary tenant in one transaction, then creates or adopts its\nGitLab group. A GitLab failure does not fail the request: the customer exists,\nand `warnings` says what is missing. Send an `Idempotency-Key` to make a retry\nsafe: a retry with the same key and request gets the first answer and changes\nnothing.",
        "operationId": "customers_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            },
            "description": "The customer was registered.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A unique key is taken (`customer_index_taken`, `short_name_taken`, `gitlab_group_taken`), the group name collides with another customer's (`gitlab_group_collision`), or no index is left (`customer_index_exhausted`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Register a customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/customers/{customer_id}": {
      "delete": {
        "description": "Archives the customer: the row, its keys, its tenants and its GitLab\ngroup stay. Archiving an archived customer succeeds and changes nothing.\nArchiving is final through v1: no operation restores an archived customer,\nand its `customer_index`, `short_name` and `gitlab_group` stay taken.",
        "operationId": "customers_delete",
        "parameters": [
          {
            "description": "The customer's id (`id` on a customer).",
            "in": "path",
            "name": "customer_id",
            "required": true,
            "schema": {
              "description": "The customer's id (`id` on a customer).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Customer Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The customer is archived.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A token created without `allow_destroy` (`destroy_not_allowed`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such customer (`customer_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Projects still exist under the customer, retired ones included (`customer_has_projects`). `blockers` counts them: `{\"projects\": n}`. `conflict`: the customer changed while being archived; retry.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Archive a customer",
        "tags": [
          "customers"
        ]
      },
      "get": {
        "description": "One customer by `id`, archived ones included. With `include=gitlab_status` the\ncustomer's GitLab group is looked up live (read-only); without it nothing outside\nthe platform is contacted.",
        "operationId": "customers_get",
        "parameters": [
          {
            "description": "The customer's id (`id` on a customer).",
            "in": "path",
            "name": "customer_id",
            "required": true,
            "schema": {
              "description": "The customer's id (`id` on a customer).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Customer Id",
              "type": "string"
            }
          },
          {
            "description": "`gitlab_status`: also ask GitLab for the customer's group. Null with a warning when GitLab cannot be reached.",
            "in": "query",
            "name": "include",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "const": "gitlab_status",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`gitlab_status`: also ask GitLab for the customer's group. Null with a warning when GitLab cannot be reached.",
              "title": "Include"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            },
            "description": "The customer.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such customer (`customer_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One customer",
        "tags": [
          "customers"
        ]
      },
      "patch": {
        "description": "Only the members in the body change. `customer_index`, `short_name`, `gitlab_group` and `edition` are frozen: sending the current value is accepted, a different one is a 422. An archived customer cannot be changed, and `status` can be set only to `active` or `suspended`, so an archived customer cannot be restored through v1.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "customers_update",
        "parameters": [
          {
            "description": "The customer's id (`id` on a customer).",
            "in": "path",
            "name": "customer_id",
            "required": true,
            "schema": {
              "description": "The customer's id (`id` on a customer).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Customer Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            },
            "description": "The customer after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such customer (`customer_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The customer is archived (`customer_archived`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A frozen key was changed (`immutable_field`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a customer",
        "tags": [
          "customers"
        ]
      }
    },
    "/licence": {
      "get": {
        "description": "The licence state as the licence gate sees it, plus what the installed document says. `growth_allowed`, `writes_allowed` and `sp_mode_enabled` are the gate's own verdicts for this state. The full `serial` and the `bundle` are returned only to a principal holding `licence-admin-global`; the serial is masked for everyone else. Never licence-gated.",
        "operationId": "licence_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Licence"
                }
              }
            },
            "description": "The licence.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "This platform's licence",
        "tags": [
          "licence"
        ]
      }
    },
    "/licence/bundle": {
      "put": {
        "description": "Verifies the `acplic1.` bundle against the pinned roots (the development root is trusted only on sandbox and dev estates), checks that it is bound to this portal's instance id, and installs it in place of the installed document.\n\nEPOCH RULE (unchanged from the portal's Licence page): a bundle installs only when its `licence_epoch` is HIGHER than the installed document's. The epochs are compared regardless of `licence_id`, so a bundle for a different licence with a lower or equal epoch is refused too. Re-sending the installed bundle is therefore a 409 `stale_epoch` with `already_installed: true`; another document whose epoch is not higher gets `already_installed: false`.\n\nA document bound to another NAME is installed, and the portal then reports `DOMAIN_MISMATCH`. Never licence-gated: this works in every state, LOCKED included. There is no operation that removes a licence. The bundle is never logged and never written to the audit log; the one audit row per install holds the licence id, the epoch and the document digest.",
        "operationId": "licence_bundle_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LicenceBundlePut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LicenceInstalled"
                }
              }
            },
            "description": "The licence was installed; it is as shown.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The portal already holds a document with the same or a higher epoch (`stale_epoch`); nothing was installed. `installed_epoch` and `installed_document_digest` describe what is installed, and `already_installed` is true when the bundle sent IS the installed document (same digest), false when it is another one with an epoch that is not higher.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The bundle does not verify (`bundle_invalid`) or is bound to another portal instance (`instance_mismatch`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Install a licence bundle",
        "tags": [
          "licence"
        ]
      }
    },
    "/licence/socket-facts": {
      "get": {
        "description": "The latest census measurement per node and whether the census hash chain is intact. Read-only: the census itself runs on its own schedule and cannot be started through this API.",
        "operationId": "licence_socket_facts",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SocketFacts"
                }
              }
            },
            "description": "The socket facts.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The socket census",
        "tags": [
          "licence"
        ]
      }
    },
    "/mcp": {
      "delete": {
        "description": "The server is stateless and issues no session id: there is nothing to\nend, and the answer is always 204.",
        "operationId": "mcp_delete",
        "responses": {
          "204": {
            "description": "Nothing to end: the server keeps no session.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "MCP: end a session",
        "tags": [
          "mcp"
        ]
      },
      "get": {
        "description": "MCP clients open a GET to listen for server-initiated messages. This\nserver sends none, so the answer is 405, which tells a client to go on\nwithout a stream.",
        "operationId": "mcp_get",
        "responses": {
          "405": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Always (`method_not_allowed`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "summary": "MCP: no server-to-client stream",
        "tags": [
          "mcp"
        ]
      },
      "post": {
        "description": "The Model Context Protocol endpoint (Streamable HTTP, stateless, JSON answers only). The body is one JSON-RPC 2.0 message or a batch. Methods: `initialize`, `notifications/initialized`, `ping`, `tools/list`, `tools/call`.\n\nEvery tool is one GET operation of this API, named by its operation id; its arguments are the operation's path and query parameters. `tools/list` shows only the tools the caller's permissions allow. A tool call runs the GET through this API with the same credentials, so the answer is exactly what a direct call would get; an error answer is `isError: true` with the problem details as text. No tool can change anything.\n\nRate limit: this POST counts as one request and every `tools/call` in it as one more, so a tool call costs two. An unauthenticated POST is a 401 problem, like every other operation.",
        "operationId": "mcp_post",
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "id": 1,
                "jsonrpc": "2.0",
                "method": "tools/call",
                "params": {
                  "arguments": {
                    "limit": 10
                  },
                  "name": "customers_list"
                }
              },
              "schema": {
                "anyOf": [
                  {
                    "properties": {
                      "id": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "integer"
                          }
                        ],
                        "description": "Absent on a notification, which gets no reply."
                      },
                      "jsonrpc": {
                        "enum": [
                          "2.0"
                        ],
                        "type": "string"
                      },
                      "method": {
                        "description": "`initialize`, `notifications/initialized`, `ping`, `tools/list` or `tools/call`; any other method is JSON-RPC error -32601.",
                        "type": "string"
                      },
                      "params": {
                        "description": "For `tools/call`: `{\"name\": <tool>, \"arguments\": {...}}`.",
                        "type": "object"
                      }
                    },
                    "required": [
                      "jsonrpc",
                      "method"
                    ],
                    "type": "object"
                  },
                  {
                    "items": {
                      "properties": {
                        "id": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "integer"
                            }
                          ],
                          "description": "Absent on a notification, which gets no reply."
                        },
                        "jsonrpc": {
                          "enum": [
                            "2.0"
                          ],
                          "type": "string"
                        },
                        "method": {
                          "description": "`initialize`, `notifications/initialized`, `ping`, `tools/list` or `tools/call`; any other method is JSON-RPC error -32601.",
                          "type": "string"
                        },
                        "params": {
                          "description": "For `tools/call`: `{\"name\": <tool>, \"arguments\": {...}}`.",
                          "type": "object"
                        }
                      },
                      "required": [
                        "jsonrpc",
                        "method"
                      ],
                      "type": "object"
                    },
                    "minItems": 1,
                    "type": "array"
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "properties": {
                        "error": {
                          "properties": {
                            "code": {
                              "type": "integer"
                            },
                            "data": {},
                            "message": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "code",
                            "message"
                          ],
                          "type": "object"
                        },
                        "id": {
                          "anyOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "integer"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "jsonrpc": {
                          "enum": [
                            "2.0"
                          ],
                          "type": "string"
                        },
                        "result": {
                          "type": "object"
                        }
                      },
                      "required": [
                        "jsonrpc",
                        "id"
                      ],
                      "type": "object"
                    },
                    {
                      "items": {
                        "properties": {
                          "error": {
                            "properties": {
                              "code": {
                                "type": "integer"
                              },
                              "data": {},
                              "message": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "code",
                              "message"
                            ],
                            "type": "object"
                          },
                          "id": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "integer"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "jsonrpc": {
                            "enum": [
                              "2.0"
                            ],
                            "type": "string"
                          },
                          "result": {
                            "type": "object"
                          }
                        },
                        "required": [
                          "jsonrpc",
                          "id"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    }
                  ]
                }
              }
            },
            "description": "The JSON-RPC reply, or an array of replies for a batch.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "202": {
            "description": "Only notifications were sent: nothing to reply.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "properties": {
                        "code": {
                          "type": "integer"
                        },
                        "data": {},
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ],
                      "type": "object"
                    },
                    "id": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "jsonrpc": {
                      "enum": [
                        "2.0"
                      ],
                      "type": "string"
                    },
                    "result": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "jsonrpc",
                    "id"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "The body is not JSON (JSON-RPC error -32700) or not a JSON-RPC message (-32600).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "MCP: read-only tools over this API",
        "tags": [
          "mcp"
        ]
      }
    },
    "/meta": {
      "get": {
        "description": "What this API and this platform are: the API version, the platform build, the\nlicence (tier, tenancy mode, modules, state) and what pipeline dispatch does here.\nNeeds a credential but no permission. Call it first: it tells an automated client\nwhich licence state its writes will meet, and whether provisioning can complete on\nthis platform (`dispatch_mode_effective`).",
        "operationId": "meta_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meta"
                }
              }
            },
            "description": "The API and platform facts.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "API and platform facts",
        "tags": [
          "meta"
        ]
      }
    },
    "/operations/{operation_id}": {
      "get": {
        "description": "Long-running work started by a 202 answer, by its id `<kind>:<native id>` (the\n`Location` header of the 202). Poll it until `status` is `succeeded` or `failed`;\n`awaiting_approval` and `awaiting_operator` wait for a person in the portal. The\nkinds: `provision` (project provisioning), `release` (a release promotion),\n`model-store-run` (a model node cache or uncache) and `order` (a tenant order placed\nin the portal, which this API can poll but not create). Reading an operation never\nchanges it. 404 `operation_not_found` for an id of an unknown kind, an unknown id,\nor one the caller may not see.",
        "operationId": "operations_get",
        "parameters": [
          {
            "in": "path",
            "name": "operation_id",
            "required": true,
            "schema": {
              "title": "Operation Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            },
            "description": "The operation.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such operation, or one the caller may not see (`operation_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One operation",
        "tags": [
          "operations"
        ]
      }
    },
    "/permissions": {
      "get": {
        "description": "Every fine-grained permission key the portal honours, `<feature>-<level>-<scope>`. `grantable` says whether it may be granted to a person; `mintable` whether an API token may carry it (v1 tokens carry `-global` keys only, never `admin`, `founder`, `ssh-console` or a key of the `api-tokens` feature). The roles catalogue also holds role names that are not permission keys (`user`, `admin`, …); those can be granted too.",
        "operationId": "permissions_list",
        "parameters": [
          {
            "description": "Only this feature's keys.",
            "in": "query",
            "name": "feature",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only this feature's keys.",
              "title": "Feature"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionPage"
                }
              }
            },
            "description": "One page of the permission catalogue.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The permission catalogue",
        "tags": [
          "users"
        ]
      }
    },
    "/projects": {
      "get": {
        "description": "Slim items: no `outputs`. Read one project for those.",
        "operationId": "projects_list",
        "parameters": [
          {
            "description": "Only this tenant's.",
            "in": "query",
            "name": "tenant_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only this tenant's.",
              "title": "Tenant Id"
            }
          },
          {
            "description": "Only this customer's, across its tenants.",
            "in": "query",
            "name": "customer_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[1-9][0-9]{0,8}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only this customer's, across its tenants.",
              "title": "Customer Id"
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "planned",
                    "provisioning",
                    "active",
                    "paused",
                    "retired"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Status"
            }
          },
          {
            "description": "Exact short name.",
            "in": "query",
            "name": "short_name",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact short name.",
              "title": "Short Name"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectPage"
                }
              }
            },
            "description": "One page of projects.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List projects",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "description": "Registers the project and compiles its manifest. Provisions NOTHING: start that with `POST /projects/{id}/provisioning`. `project_index` is allocated when omitted. A token that creates a project is recorded as `registered_by`. Send an `Idempotency-Key` to make a retry safe: a retry with the same key and request gets the first answer and changes nothing.",
        "operationId": "projects_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            },
            "description": "The project was registered.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A unique key is taken, or no index is left (`project_index_exhausted`), or the customer is archived (`customer_archived`). The unique keys are checked in ONE fixed order — `short_name`, `project_index` (when sent), `primary_domain`, `gitlab_repo_slug` — and the FIRST one taken is the answer: `code` is `<key>_taken` and `field` names it. `conflicts` lists EVERY taken key in that order, each as `{field, code, project_id}` (`project_id`: the project holding it, null when a concurrent create took it). Retired projects keep their keys, so a retired project's values stay taken.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`), an impossible combination (`invalid_combination`), the manifest compiler refused the input (`manifest_refused`, `windows_requires_vm_backend`; `detail` is its message), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Register a project",
        "tags": [
          "projects"
        ]
      }
    },
    "/projects/{project_id}": {
      "delete": {
        "description": "Retires the project: `status` becomes `retired` and that is all. Its `project_index`, `short_name` and `primary_domain` stay reserved, and nothing on the substrate is touched — no VM, DNS record, secrets store path or repository is removed. There is no way to wipe or tear down a project through this API. Retiring a retired project is a 204.",
        "operationId": "projects_delete",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The project is retired.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A token created without `allow_destroy` (`destroy_not_allowed`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An ATAILA platform project (`platform_project_read_only`), an orchestration is running on it (`orchestration_in_progress`), or it changed while being retired and could not be (`project_not_retirable`; retry).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Retire a project",
        "tags": [
          "projects"
        ]
      },
      "get": {
        "description": "One project by `id`, retired ones and ATAILA's own platform projects (`is_self`)\nincluded, with `outputs`: the names its provisioning produces or will produce\n(public URLs, repositories, namespaces). Provisioning progress is `GET\n/projects/{id}/provisioning`.",
        "operationId": "projects_get",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            },
            "description": "The project.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One project",
        "tags": [
          "projects"
        ]
      },
      "patch": {
        "description": "Changes the record and recompiles its manifest; dispatches nothing. The provisioning stages the change leaves stale are marked and returned as `stale_stages`; `POST /projects/{id}/provisioning` re-applies exactly those. Only a stage already done can be stale: one never applied is applied with the new manifest by the next start anyway. Frozen: `project_index`, `short_name`, `gitlab_repo_slug`, `tenant_id`, `deployment_backend`, `network_only`, `primary_domain` (the current value is accepted, a different one is a 422). The create rules are checked on the merged result.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "projects_update",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectUpdated"
                }
              }
            },
            "description": "The project after the change, with the stages it left stale.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An ATAILA platform project (`platform_project_read_only`), a retired one (`project_retired`), or the project's tenant has no customer any more (`tenant_has_no_customer`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A frozen key was changed (`immutable_field`), an impossible combination (`invalid_combination`), a compiler refusal (`manifest_refused`, `windows_requires_vm_backend`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a project",
        "tags": [
          "projects"
        ]
      }
    },
    "/projects/{project_id}/members": {
      "get": {
        "description": "The people given a role on this one project, in `user_id` order. Tenant members\nreach the project through the tenant and are not listed here.",
        "operationId": "project_members_list",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMemberPage"
                }
              }
            },
            "description": "One page of the project's members.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A project's members",
        "tags": [
          "projects"
        ]
      }
    },
    "/projects/{project_id}/members/{user_id}": {
      "delete": {
        "description": "Removes the membership. Not destroy-gated: it needs the write permission only. Allowed on a retired project.",
        "operationId": "project_members_delete",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The member was removed.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`) or member (`member_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An ATAILA platform project (`platform_project_read_only`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Remove a member",
        "tags": [
          "projects"
        ]
      },
      "get": {
        "description": "One person's role on the project. 404 `member_not_found` when they have no\nproject-level role (a tenant member may still reach the project).",
        "operationId": "project_members_get",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMember"
                }
              }
            },
            "description": "The project member.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`) or member (`member_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One project member",
        "tags": [
          "projects"
        ]
      },
      "put": {
        "description": "201 when the membership was created, 200 when an existing one was set. `gitlab_role` is recorded and NOT enforced: nothing is changed in GitLab.",
        "operationId": "project_members_put",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectMemberPut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMember"
                }
              }
            },
            "description": "The existing member's role was set.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMember"
                }
              }
            },
            "description": "The member was added.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`) or user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An ATAILA platform project (`platform_project_read_only`), a retired one (`project_retired`), or the user may not be a member (`member_not_eligible`: only ATAILA staff and members of a tenant of the project's customer may).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`gitlab_role` above the customer cap (`gitlab_role_above_cap`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Add a member or change their role",
        "tags": [
          "projects"
        ]
      }
    },
    "/projects/{project_id}/prod-lock": {
      "get": {
        "description": "While `locked`, no data copy may target PROD. Code promotion is not affected.",
        "operationId": "prod_lock_get",
        "parameters": [
          {
            "description": "The project's id.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProdLock"
                }
              }
            },
            "description": "The PROD data lock.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project, or outside your scope (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The PROD data lock",
        "tags": [
          "releases"
        ]
      },
      "put": {
        "description": "The lock protects PROD DATA: while it is set, the portal refuses every data copy into PROD, so PROD stays the source of truth for its data. It does NOT block code promotion into PROD.\n\n`{\"locked\": true}` locks. Unlocking needs `confirm_unlock` equal to the project's short name. Setting the state it already has changes nothing (the lock keeps its time and author).",
        "operationId": "prod_lock_put",
        "parameters": [
          {
            "description": "The project's id.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProdLockPut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProdLock"
                }
              }
            },
            "description": "The PROD data lock after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project, or outside your scope (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The project is retired (`project_retired`): its PROD lock no longer changes.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Unlocking without `confirm_unlock` equal to the project's short name (`unlock_not_confirmed`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Set the PROD data lock",
        "tags": [
          "releases"
        ]
      }
    },
    "/projects/{project_id}/provisioning": {
      "get": {
        "description": "Read from the database only. `converged` is true when every stage is done and none is stale; `provisioned` additionally requires that no stage was simulated. On a platform whose `dispatch_mode` is `dryrun` nothing is ever executed and provisioning never completes; under `simulate` stages are marked done without running, so `converged` can be true while `provisioned` is false.",
        "operationId": "project_provisioning_get",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Provisioning"
                }
              }
            },
            "description": "The provisioning state.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A project's provisioning state",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "description": "Starts the stage engine and answers 202 with an operation (`provision:<id>`) to poll at `GET /operations/{id}` (also the `Location` header). When stages are stale it re-applies exactly those (apply-pending); otherwise it applies every stage not yet done (apply-all). The operation is `awaiting_operator` when a stage needs a person in the portal, and never succeeds on a `dryrun` platform; on a `simulate` platform it succeeds with `simulated: true` and provisions nothing. Send an `Idempotency-Key`: a retry with the same key gets the same operation and never starts a second orchestration.",
        "operationId": "project_provisioning_start",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          },
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            },
            "description": "Provisioning started: poll the operation.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "An ATAILA platform project (`platform_project_read_only`), a retired one (`project_retired`), or an orchestration already holds the project (`orchestration_in_progress`; `operation_id` names it).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Start provisioning",
        "tags": [
          "projects"
        ]
      }
    },
    "/projects/{project_id}/release-operations": {
      "get": {
        "description": "Newest first. Includes the data copies booked in the portal.",
        "operationId": "release_operations_list",
        "parameters": [
          {
            "description": "The project's id.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          },
          {
            "description": "Only operations in this status.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "pending",
                    "awaiting_approval",
                    "running",
                    "succeeded",
                    "failed"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only operations in this status.",
              "title": "Status"
            }
          },
          {
            "in": "query",
            "name": "target_env",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "sandbox",
                    "dev",
                    "uat",
                    "prod"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Target Env"
            }
          },
          {
            "description": "Excludes data copies (no component).",
            "in": "query",
            "name": "component",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "enum": [
                    "app-api",
                    "www"
                  ],
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Excludes data copies (no component).",
              "title": "Component"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseOperationPage"
                }
              }
            },
            "description": "One page of release operations, newest first.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project, or outside your scope (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Release history of a project",
        "tags": [
          "releases"
        ]
      }
    },
    "/projects/{project_id}/release-promotions": {
      "post": {
        "description": "Books a promotion of one component into one environment and answers `202` with an operation (`release:<id>`) and its `Location`. Poll `GET /operations/{id}` until `succeeded` or `failed`.\n\n* `dev` and `uat` start at once.\n* `dev` promotions deploy a named build; the API cannot verify it exists before dispatch. Its `version` is required and is not checked against any reported version (DEV has no environment below it).\n* `prod` is a REQUEST: the operation stays `awaiting_approval` until a person approves or rejects it in the portal's release management. This API cannot approve, reject, release express or copy data. A rejection ends it as `failed` with the reason. Approval needs no second person when the approver writes a note; a request made with a token counts as made by the token's owner and by whoever minted it.\n\nKubernetes projects only. The version promoted into `uat` or `prod` is the one the environment below last reported (`dev` for `uat`, `uat` for `prod`). Send an `Idempotency-Key`: a retried request then never books a second deployment.",
        "operationId": "release_promotions_create",
        "parameters": [
          {
            "description": "The project's id.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          },
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReleasePromotionCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            },
            "description": "The promotion was booked: poll the operation.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project, or outside your scope (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The project is retired (`project_retired`: a retired project takes no release), or the Idempotency-Key already booked a different operation (`idempotency_key_reused`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A VM project (`vm_projects_unsupported`); the component does not exist (`component_not_enabled`); the version is not what the source environment last reported, or it reports none (`version_not_at_source`); a `dev` promotion without a version (`version_required`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Request a promotion",
        "tags": [
          "releases"
        ]
      }
    },
    "/projects/{project_id}/release-state": {
      "get": {
        "description": "Per environment and component, the version a release pipeline LAST REPORTED, when and by whom — recorded when a deploy reports success, not probed live. Also the PROD DATA lock and the operations still open.",
        "operationId": "release_state_get",
        "parameters": [
          {
            "description": "The project's id.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id.",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseState"
                }
              }
            },
            "description": "The release state.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project, or outside your scope (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Release state of a project",
        "tags": [
          "releases"
        ]
      }
    },
    "/projects/{project_id}/stages": {
      "get": {
        "description": "The stage grid of the portal's Plan page, read-only and from the database only.",
        "operationId": "project_stages_list",
        "parameters": [
          {
            "description": "The project's id (`id` on a project).",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "description": "The project's id (`id` on a project).",
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageGrid"
                }
              }
            },
            "description": "The stage grid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such project (`project_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A project's provisioning stages",
        "tags": [
          "projects"
        ]
      }
    },
    "/release-operations/{release_operation_id}": {
      "get": {
        "description": "One release operation (a promotion and what became of it) by `id`, as recorded. The\nsame one is the operation `release:<id>` at `GET /operations/{id}`. Only operations\nof projects within the caller's reach are visible (for a token, every project); any\nother id answers 404.",
        "operationId": "release_operations_get",
        "parameters": [
          {
            "in": "path",
            "name": "release_operation_id",
            "required": true,
            "schema": {
              "pattern": "^[1-9][0-9]{0,8}$",
              "title": "Release Operation Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleaseOperation"
                }
              }
            },
            "description": "The release operation.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such operation, or its project is outside your scope (`release_operation_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One release operation",
        "tags": [
          "releases"
        ]
      }
    },
    "/tenants": {
      "get": {
        "description": "The tenants of this platform, in `slug` order. The filters are exact and combine:\n`customer_id` (that customer's tenants), `slug`.",
        "operationId": "tenants_list",
        "parameters": [
          {
            "description": "Only this customer's tenants.",
            "in": "query",
            "name": "customer_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[1-9][0-9]{0,8}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only this customer's tenants.",
              "title": "Customer Id"
            }
          },
          {
            "description": "Exact slug.",
            "in": "query",
            "name": "slug",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact slug.",
              "title": "Slug"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantPage"
                }
              }
            },
            "description": "One page of tenants.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List tenants",
        "tags": [
          "tenants"
        ]
      },
      "post": {
        "description": "Registers a further tenant of an existing customer (a customer's primary\ntenant is made with the customer). A person signed in to the portal becomes\nthe tenant's `owner`; a token's owner does not, so a tenant created with a\ntoken starts with no members (`PUT /tenants/{id}/memberships/{user_id}` adds\nthem). `customer_id` and `slug` are frozen once created. Send an\n`Idempotency-Key` to make a retry safe: a retry with the same key and request\ngets the first answer and changes nothing.",
        "operationId": "tenants_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "description": "The tenant was registered.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The slug is taken (`tenant_slug_taken`) or the customer is archived (`customer_archived`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such customer (`customer_not_found`) or router (`default_router_not_found`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Register a tenant",
        "tags": [
          "tenants"
        ]
      }
    },
    "/tenants/{tenant_id}": {
      "delete": {
        "description": "Deletes the tenant only when nothing but memberships hangs off it: no project of any status, no contract, no helpdesk record, no attributed resource, no live AI gateway key (a deleted key's registry row is kept and detached). Its memberships go with it, and its SSO `/tenants/<slug>` groups are removed. Service grants are NOT revoked: a user's grants are held per customer, not per tenant, and stay in force until revoked in the portal.",
        "operationId": "tenants_delete",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The tenant was deleted.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A token created without `allow_destroy` (`destroy_not_allowed`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The tenant is a customer's primary tenant (`tenant_is_primary`) or is not empty: `tenant_has_projects`, `tenant_has_contracts`, `tenant_has_helpdesk_records`, `tenant_has_attributed_resources`, `tenant_has_ai_gateway_keys` (live AI gateway keys). `blockers` counts each. `tenant_in_use`: something else still refers to the tenant (no `blockers`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Delete an empty tenant",
        "tags": [
          "tenants"
        ]
      },
      "get": {
        "description": "One tenant by `id`, with its project and member counts.",
        "operationId": "tenants_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "description": "The tenant.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One tenant",
        "tags": [
          "tenants"
        ]
      },
      "patch": {
        "description": "Only the members in the body change. `customer_id` and `slug` are frozen: sending the current value is accepted, a different one is a 422.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "tenants_update",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/TenantPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tenant"
                }
              }
            },
            "description": "The tenant after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A frozen key was changed (`immutable_field`), no such router (`default_router_not_found`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a tenant",
        "tags": [
          "tenants"
        ]
      }
    },
    "/tenants/{tenant_id}/memberships": {
      "get": {
        "description": "The tenant's members and their roles, in `user_id` order.",
        "operationId": "tenant_memberships_list",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembershipPage"
                }
              }
            },
            "description": "One page of the tenant's memberships.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A tenant's memberships",
        "tags": [
          "tenants"
        ]
      }
    },
    "/tenants/{tenant_id}/memberships/{user_id}": {
      "delete": {
        "description": "Removes the user's membership of the tenant and re-syncs their SSO groups. This is NOT destroy-gated: it needs the write permission only, not a token created with `allow_destroy`. Service grants are NOT revoked: a user's grants are held per customer, not per tenant, and stay in force until revoked in the portal.",
        "operationId": "tenant_memberships_delete",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The membership was removed.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`) or membership (`membership_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Remove a member",
        "tags": [
          "tenants"
        ]
      },
      "get": {
        "description": "One person's membership of the tenant. 404 `membership_not_found` when they are not\na member.",
        "operationId": "tenant_memberships_get",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Membership"
                }
              }
            },
            "description": "The membership.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`) or membership (`membership_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One membership",
        "tags": [
          "tenants"
        ]
      },
      "put": {
        "description": "201 when the membership was created, 200 when an existing one was set.",
        "operationId": "tenant_memberships_put",
        "parameters": [
          {
            "in": "path",
            "name": "tenant_id",
            "required": true,
            "schema": {
              "title": "Tenant Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MembershipPut"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Membership"
                }
              }
            },
            "description": "The existing membership's role was set.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Membership"
                }
              }
            },
            "description": "The membership was created.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such tenant (`tenant_not_found`) or user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Add a member or change their role",
        "tags": [
          "tenants"
        ]
      }
    },
    "/users": {
      "get": {
        "description": "The people on this platform, in `id` order; service accounts only with `kind`\n`service` or `all`. The filters combine (all must hold): `email` and `username` are\nexact and case-insensitive, `is_active`, `tenant_id` (members of that tenant),\n`customer_id` (members of any of its tenants), `role` (holders of that role).\nDeactivated people are listed unless `is_active` is `true`.",
        "operationId": "users_list",
        "parameters": [
          {
            "description": "Exact address, compared lower-cased.",
            "in": "query",
            "name": "email",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact address, compared lower-cased.",
              "title": "Email"
            }
          },
          {
            "description": "Exact username, case-insensitive.",
            "in": "query",
            "name": "username",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Exact username, case-insensitive.",
              "title": "Username"
            }
          },
          {
            "description": "`human` (default) leaves service accounts out.",
            "in": "query",
            "name": "kind",
            "required": false,
            "schema": {
              "default": "human",
              "description": "`human` (default) leaves service accounts out.",
              "enum": [
                "human",
                "service",
                "all"
              ],
              "title": "Kind",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "is_active",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "boolean"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Is Active"
            }
          },
          {
            "description": "Only members of this tenant.",
            "in": "query",
            "name": "tenant_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "format": "uuid",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only members of this tenant.",
              "title": "Tenant Id"
            }
          },
          {
            "description": "Only members of one of this customer's tenants.",
            "in": "query",
            "name": "customer_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "pattern": "^[1-9][0-9]{0,8}$",
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only members of one of this customer's tenants.",
              "title": "Customer Id"
            }
          },
          {
            "description": "Only holders of this role.",
            "in": "query",
            "name": "role",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Only holders of this role.",
              "title": "Role"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserPage"
                }
              }
            },
            "description": "One page of users.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List users",
        "tags": [
          "users"
        ]
      },
      "post": {
        "description": "Creates the person with the role `user` and runs the portal's provisioning: username, SSO account, and — with `needs_git_access` — a GitLab account and group membership. No password is set and none is ever returned: the person cannot sign in until an operator resets their password in the portal or they use the self-service reset. A provisioning step that fails is a `warnings` entry (`provisioning_<step>_failed`) and `provisioning_status` is `ok`, `partial` or `error`; the person exists either way, so the answer is 201. On a platform with no SSO configured at all the SSO step is skipped, not failed: `provisioning_status` is `partial` with a `sso_not_configured` warning (`error` stays for a configured SSO that failed). `Idempotency-Key` is honoured.",
        "operationId": "users_create",
        "parameters": [
          {
            "description": "Makes a retry safe: for 24 hours, the same key with the same request (method, path, query and body) answers with the stored response (`Idempotent-Replayed: true`) instead of doing the work again. The same key with a different request is a 409 `idempotency_key_reused`; while the first request is still running it is a 429 `idempotency_request_in_progress` with `Retry-After`. 1-255 printable characters without spaces (400 `invalid_idempotency_key` otherwise); a UUID is a good key. Keys are scoped to the calling account.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "maxLength": 255,
              "minLength": 1,
              "pattern": "^[!-~]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            },
            "description": "The person was created.",
            "headers": {
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The e-mail address (`email_taken`) or username (`username_taken`) is taken, deactivated users included.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The Windows name derived from the name, or the one given, is not usable (`invalid_directory_name`, with `field`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create a person",
        "tags": [
          "users"
        ]
      }
    },
    "/users/{user_id}": {
      "delete": {
        "description": "Answers 204 with no body, like every v1 `DELETE`. A downstream step that fails does not undo the deactivation and is not in this answer: it is logged and kept on the audit row (`warnings`). To get the step outcomes in the answer, deactivate with `PATCH` `{\"is_active\": false}` instead: the same gate, refusals and steps, answered 200 with the user and its `warnings`. Deactivation never deletes. It sets `is_active` to false and then, at once: clears the cached active state so signed-in sessions and API tokens stop on the next request; converges the SSO account, which disables it, and ends its open SSO sessions; removes the person from the remote desktop group; and blocks their GitLab account when they have one. Each of those steps that fails is a warning (`sso_disable_failed`, `sso_logout_failed`, `sso_not_configured`, `vdi_revoke_failed`, `gitlab_block_failed`, `gitlab_not_configured`, `session_cache_not_cleared`); the deactivation stands. Repeating it repeats the steps. Refused (409) for your own account (`cannot_deactivate_self`), the last active admin (`last_active_admin`) and a service account (`service_account_managed_elsewhere`). Tenant memberships, role grants and service grants are kept, so re-activating restores them. NOT done: the person's account on the partner portal is not disabled; disable it there.",
        "operationId": "users_delete",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The person is deactivated.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A token created without `allow_destroy` (`destroy_not_allowed`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Your own account (`cannot_deactivate_self`), the last active admin (`last_active_admin`), or a service account (`service_account_managed_elsewhere`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Deactivate a user",
        "tags": [
          "users"
        ]
      },
      "get": {
        "description": "One person (or service account) by `id`, deactivated ones included. No password and\nno SSO or GitLab identifier is ever returned; `sso_linked` and `gitlab_linked` say\nwhether those accounts exist.",
        "operationId": "users_get",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            },
            "description": "The user.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One user",
        "tags": [
          "users"
        ]
      },
      "patch": {
        "description": "Only the members in the body change. `username` and `ad_username` are create-only: sending the current value is accepted, any other value is a 422 `immutable_field` naming the field, whether or not the person has an SSO account (`sso_linked`). Changing `email` answers with an `email_keyed_grants_affected` warning. `is_active: false` is a deactivation, with the same destroy gate, refusals and steps as `DELETE`; `is_active: true` re-activates (the SSO account is enabled and the GitLab account unblocked; desktop access is not restored). Switching `needs_git_access` on runs the GitLab provisioning step now; switching it off removes no account. Changes that reach the SSO account are converged before the answer; a failure there is a `sso_sync_failed` warning.\n\nThe body is a JSON Merge Patch (RFC 7396), sent as `application/merge-patch+json` or `application/json`: a member that is omitted is left unchanged, and a member set to `null` clears that field where clearing is allowed (the schema marks those fields nullable; `null` for any other field is a 422).",
        "operationId": "users_update",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserPatch"
              }
            },
            "application/merge-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/UserPatch"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            },
            "description": "The user after the change.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "`is_active: false` with a token created without `allow_destroy` (`destroy_not_allowed`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The e-mail address is taken (`email_taken`), the user is a service account (`service_account_managed_elsewhere`), or a deactivation is refused (`cannot_deactivate_self`, `last_active_admin`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A create-only field was changed (`immutable_field`, with `field`: `username` or `ad_username`), or the body is invalid.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Change a user",
        "tags": [
          "users"
        ]
      }
    },
    "/users/{user_id}/roles": {
      "get": {
        "description": "Every role the person holds, in `role` order.",
        "operationId": "user_roles_list",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "description": "Page size.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "description": "Page size.",
              "maximum": 200,
              "minimum": 1,
              "title": "Limit",
              "type": "integer"
            }
          },
          {
            "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "`next_cursor` from the previous page; omit it for the first page. A cursor this list did not issue is a 400 `invalid_cursor`.",
              "title": "Cursor"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleGrantPage"
                }
              }
            },
            "description": "One page of the user's role grants.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "A user's role grants",
        "tags": [
          "users"
        ]
      }
    },
    "/users/{user_id}/roles/{role}": {
      "delete": {
        "description": "Removes one role. Not destroy-gated: it needs the write permission only. The portal's role rules apply: the role must exist in the roles catalogue (`unknown_role`, 422); a key that is not grantable is refused (`role_not_grantable`, 400); `founder` and `ssh-console` are granted only by a holder and never to yourself; the last active admin keeps `admin`, and nobody removes their own; a user keeps at least one role (`last_role`, 409). An API token can never grant or revoke `admin`, `founder`, `ssh-console` or a key of the `api-tokens` feature (`role_not_manageable_by_token`: managing tokens takes a browser session), can never change the roles of its own account (`token_cannot_change_own_roles`), and grants or revokes only a role within its own effective scopes (`role_not_held_by_token`), all 403; a browser session is held to none of these three and keeps the portal's rules. The change is converged into SSO before the answer; a failure there is a `sso_sync_failed` warning.",
        "operationId": "user_roles_delete",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "role",
            "required": true,
            "schema": {
              "title": "Role",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The role was revoked.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A role rule refused it (`role_not_manageable_by_token`, `token_cannot_change_own_roles`, `role_not_held_by_token`, `cannot_remove_own_admin`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`) or grant (`role_grant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The last active admin's `admin` (`last_active_admin`), the user's last role (`last_role`), or a service account (`service_account_managed_elsewhere`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Revoke a role",
        "tags": [
          "users"
        ]
      },
      "get": {
        "description": "Whether the person holds one role: the grant, or 404 `role_grant_not_found`.",
        "operationId": "user_roles_get",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "role",
            "required": true,
            "schema": {
              "title": "Role",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleGrant"
                }
              }
            },
            "description": "The role grant.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`) or grant (`role_grant_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "One role grant",
        "tags": [
          "users"
        ]
      },
      "put": {
        "description": "201 when the role was granted, 200 when the user already held it (nothing changes). No body. The portal's role rules apply: the role must exist in the roles catalogue (`unknown_role`, 422); a key that is not grantable is refused (`role_not_grantable`, 400); `founder` and `ssh-console` are granted only by a holder and never to yourself; the last active admin keeps `admin`, and nobody removes their own; a user keeps at least one role (`last_role`, 409). An API token can never grant or revoke `admin`, `founder`, `ssh-console` or a key of the `api-tokens` feature (`role_not_manageable_by_token`: managing tokens takes a browser session), can never change the roles of its own account (`token_cannot_change_own_roles`), and grants or revokes only a role within its own effective scopes (`role_not_held_by_token`), all 403; a browser session is held to none of these three and keeps the portal's rules. The change is converged into SSO before the answer; a failure there is a `sso_sync_failed` warning.",
        "operationId": "user_roles_put",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "title": "User Id",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "role",
            "required": true,
            "schema": {
              "title": "Role",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleGrant"
                }
              }
            },
            "description": "The user already held the role; nothing changed.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RoleGrant"
                }
              }
            },
            "description": "The role was granted.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The key is not grantable (`role_not_grantable`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "A role rule refused it (`role_not_manageable_by_token`, `token_cannot_change_own_roles`, `role_not_held_by_token`, `privileged_role_requires_holding_it`, `cannot_grant_to_self`). Also: the caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such user (`user_not_found`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The user is a service account (`service_account_managed_elsewhere`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "No such role in the catalogue (`unknown_role`).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Grant a role",
        "tags": [
          "users"
        ]
      }
    },
    "/whoami": {
      "get": {
        "description": "Who is calling and what they may do right now. `scopes` are the EFFECTIVE\npermissions: for a token, its scopes that its owner still holds, so a scope the\nowner has lost is not there; `token.granted_scopes` is what the token was created\nwith. `expires_at` is when the credential stops working. Needs a credential but no\npermission.",
        "operationId": "whoami_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Whoami"
                }
              }
            },
            "description": "The calling principal.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Not authenticated: no `Authorization: Bearer` header (`not_authenticated`), or the credential is refused (`token_invalid`, `token_expired`, `token_revoked`, `principal_disabled`, `token_ip_not_allowed`).",
            "headers": {
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The caller lacks a permission the operation needs (`forbidden`; `required` lists the keys, any one of which would do), or the licence refuses a change (`licence_locked`, `licence_restricted`, `licence_required`, with `state` and `remedy`; never retry a `licence_*` code).",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "More than 600 requests in a minute with this token (`rate_limited`), or the first request with this `Idempotency-Key` is still running (`idempotency_request_in_progress`). Retry after `Retry-After`.",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "The platform cannot answer right now (`unavailable`; retry after `Retry-After`), or API tokens are not configured on it (`api_tokens_unconfigured`; an operator must act).",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          },
          "default": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Problem details (RFC 9457)",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/X-Request-ID"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The calling principal",
        "tags": [
          "meta"
        ]
      }
    }
  },
  "tags": [
    {
      "description": "What this API and platform are, and who is calling.",
      "name": "meta"
    },
    {
      "description": "Long-running work: poll until succeeded or failed.",
      "name": "operations"
    },
    {
      "description": "Customers (companies) on this platform.",
      "name": "customers"
    },
    {
      "description": "Tenants of a customer and their memberships.",
      "name": "tenants"
    },
    {
      "description": "Users, role grants and the permission catalog.",
      "name": "users"
    },
    {
      "description": "Projects, provisioning and project members.",
      "name": "projects"
    },
    {
      "description": "Release promotions, release state and the PROD lock.",
      "name": "releases"
    },
    {
      "description": "AI gateway virtual keys and serving tiers.",
      "name": "ai-gateway"
    },
    {
      "description": "The AI model catalogue and node caches.",
      "name": "ai-models"
    },
    {
      "description": "AI Center nodes, DGX clusters and the launch catalogue (read-only).",
      "name": "ai-nodes"
    },
    {
      "description": "This platform's licence.",
      "name": "licence"
    },
    {
      "description": "This platform's branding.",
      "name": "brand"
    },
    {
      "description": "The platform audit log: every recorded change, read-only.",
      "name": "audit"
    },
    {
      "description": "Model Context Protocol: every GET operation as a read-only tool.",
      "name": "mcp"
    }
  ]
}
