{
  "openapi": "3.1.0",
  "info": {
    "title": "Updawg API",
    "description": "The Updawg portal and public REST API.",
    "license": {
      "name": "proprietary"
    },
    "version": "0.1.0"
  },
  "servers": [
    {
      "url": "https://api.updawg.net",
      "description": "Production"
    }
  ],
  "paths": {
    "/v1/auth/logout": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/logout`.",
        "description": "Extracting [`CurrentUser`] is what makes this CSRF-protected: without it a\ncross-site page could sign somebody out, which is not a disaster and is\nstill not something anybody else gets to do.",
        "operationId": "auth_logout",
        "responses": {
          "204": {
            "description": "Signed out. Clears the session cookie."
          },
          "400": {
            "description": "A region token, which has no session here to end: sign out at the directory (DAWG-296).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/magic-link": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/magic-link`.",
        "operationId": "auth_request_magic_link",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MagicLinkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Accepted. ⚠️ The same answer whether or not the address belongs to anybody — the endpoint must not be usable to ask whether somebody has an account. **202, not 204**: the mail is sent after the answer, and a client that waits for delivery will wait for ever."
          },
          "400": {
            "description": "Not an address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Too many links asked for this address, or from this source. The same for every address, so it says nothing about who has an account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/magic-link/verify": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/magic-link/verify`.",
        "operationId": "auth_verify_magic_link",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Signed in. Sets the session cookie.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignedIn"
                }
              }
            }
          },
          "400": {
            "description": "A body that is not `{\"token\": …}` (DAWG-246).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "The token is unknown, used or expired — one answer for all three, because the caller's next move is the same as if they had never signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "The address's organization requires single sign-on: `sso-required` (DAWG-155).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/oidc/{provider}/callback": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/oidc/{provider}/callback`.",
        "operationId": "oidc_callback",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "description": "`github`, `google`, `microsoft` or `apple`, as configured.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code",
            "in": "query",
            "description": "The authorization code.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Must match the one this side issued.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "error",
            "in": "query",
            "description": "Set when the person declined.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "Redirect back into the portal, signed in or not."
          },
          "400": {
            "description": "A state that was not issued here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/oidc/{provider}/callback`: the same, for a provider that\nposts its answer (Apple).",
        "operationId": "oidc_callback_form",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "description": "`apple`, as configured.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/Callback"
              }
            }
          },
          "required": true
        },
        "responses": {
          "303": {
            "description": "Redirect back into the portal, signed in or not."
          },
          "400": {
            "description": "The body is not a form.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/oidc/{provider}/start": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/oidc/{provider}/start`.",
        "operationId": "oidc_start",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "description": "`github`, `google`, `microsoft` or `apple`, as configured.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "Redirect to the provider."
          },
          "400": {
            "description": "No such sign-in provider.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/providers": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/providers`.",
        "operationId": "oidc_providers",
        "responses": {
          "200": {
            "description": "Which external sign-in providers are configured (DAWG-243).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvidersBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/sign-up": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/sign-up`.",
        "operationId": "auth_sign_up",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignUpRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Accepted: a mail is on its way. ⚠️ The same answer whether or not the address already has an account — one that has is sent a sign-in link instead."
          },
          "400": {
            "description": "Not an address, or a name missing or too long.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "The address's domain belongs to an organization that requires single sign-on: `sso-required`. About the domain, not the person (DAWG-155). Or this deployment does not let people make their own accounts: `sign-up-closed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Too many links asked for this address, or from this source.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/sign-up/verify": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/auth/sign-up/verify`.",
        "operationId": "auth_verify_sign_up",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignUpVerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The account and its organization exist, and this is a session for it. Sets the session cookie.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignedIn"
                }
              }
            }
          },
          "400": {
            "description": "A body that is not `{\"token\": …}`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "The token is unknown, used or expired — one answer for all three.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "The address's organization requires single sign-on: `sso-required` (DAWG-155), or sign-up has closed since the form was sent: `sign-up-closed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/sso/callback": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/sso/callback`.",
        "operationId": "sso_callback",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "description": "The authorization code.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "description": "Must match the one this side issued.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "error",
            "in": "query",
            "description": "Set when the provider refused.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "Back into the portal: signed in, or to the sign-in page with `?error=sso_…`."
          }
        }
      }
    },
    "/v1/auth/sso/discover": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/sso/discover`.",
        "operationId": "sso_discover",
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "description": "The address somebody typed on the sign-in page.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whether this address's domain signs in through an organization's provider. About the domain, never the person: the answer is the same whether or not the address has an account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoDiscoverBody"
                }
              }
            }
          },
          "400": {
            "description": "No `email`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/sso/{org}/start": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/auth/sso/{org}/start`.",
        "operationId": "sso_start",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "To the organization's provider; or back to the portal's sign-in page with `?error=sso_unavailable` when it has no usable connection."
          }
        }
      }
    },
    "/v1/digests/unsubscribe": {
      "post": {
        "tags": [
          "notifications"
        ],
        "summary": "`POST /v1/digests/unsubscribe`.",
        "operationId": "digest_unsubscribe",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "description": "From the digest's link.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "That digest is off. Nothing else changed."
          },
          "400": {
            "description": "No token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "Not a token, or one older than sixty days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/integrations/slack/callback": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/integrations/slack/callback`.",
        "operationId": "slack_callback",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "error",
            "in": "query",
            "description": "`access_denied` when the person said no.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "To the portal's settings: `slack=installed`, or `slack=failed` and a `reason` (`denied`, `expired`, `refused`, `unavailable`)."
          }
        }
      }
    },
    "/v1/integrations/slack/commands": {
      "post": {
        "tags": [
          "slack"
        ],
        "summary": "`POST /v1/integrations/slack/commands`.",
        "operationId": "slack_commands",
        "requestBody": {
          "description": "A slash command, byte for byte as Slack signed it.",
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The answer (DAWG-315): only for the person who typed it, or in the channel when it ends with `share`. With `blocks` as Slack lays them out, `text` the fallback. One that takes longer than Slack's three seconds allow says so, and its answer follows through the command's `response_url`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackReplyBody"
                }
              }
            }
          },
          "400": {
            "description": "Not signed by this region's Slack app, or more than five minutes old.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no Slack app: `slack-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/integrations/slack/events": {
      "post": {
        "tags": [
          "slack"
        ],
        "summary": "`POST /v1/integrations/slack/events` (DAWG-319, DAWG-316, DAWG-317).",
        "operationId": "slack_events",
        "requestBody": {
          "description": "One of Slack's Events API deliveries, byte for byte as Slack signed it.",
          "content": {
            "application/json": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "`url_verification`: its challenge, which is how Slack checks this address when the app's manifest is saved. Anything else: `{}` at once, and the event acted on after — `app_uninstalled` and `tokens_revoked` remove the installation, `app_home_opened` draws the Home tab, `link_shared` unfurls a link to the portal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackChallengeBody"
                }
              }
            }
          },
          "400": {
            "description": "Not signed by this region's Slack app, more than five minutes old, or not JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no Slack app: `slack-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/integrations/slack/interactions": {
      "post": {
        "tags": [
          "slack"
        ],
        "summary": "`POST /v1/integrations/slack/interactions` (DAWG-313).",
        "operationId": "slack_interactions",
        "requestBody": {
          "description": "A click on a proposal's message, or the reject form submitted, byte for byte as Slack signed it.",
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Received, at once. What it came to goes back to Slack: a reply only the person sees, and the message edited when the proposal changes. For the reject form: `clear`, or `errors` when the reason is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackInteractionReply"
                }
              }
            }
          },
          "400": {
            "description": "Not signed by this region's Slack app, more than five minutes old, or no payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no Slack app: `slack-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/invitations/accept": {
      "post": {
        "tags": [
          "organizations"
        ],
        "summary": "`POST /v1/invitations/accept`.",
        "description": "Not under `/orgs/{org}`, because the caller is not in one yet — that is what\nthey are doing. Which organization it is comes from the token.",
        "operationId": "invitations_accept",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Joined.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JoinedBody"
                }
              }
            }
          },
          "400": {
            "description": "The token is unknown, used, expired or for somebody else — one answer for all four.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "Unknown, expired, already taken up or withdrawn — one answer for all four, so that somebody holding a guess cannot find out which part of it was right.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "⚠️ The invitation is for a different address. The one distinction that is safe to make, because whoever is asking is holding a token that was mailed to that address — and a refusal that does not name it is one nobody can act on.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/invitations/join": {
      "post": {
        "tags": [
          "organizations"
        ],
        "summary": "`POST /v1/invitations/join`.",
        "description": "For somebody with no account: makes one for the address the invitation was\nsent to, takes the invitation up, and signs them in.",
        "operationId": "invitations_join",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JoinRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The account exists, has joined, and this is a session for it. Sets the session cookie.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignedIn"
                }
              }
            }
          },
          "400": {
            "description": "No name, or one too long.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Joined, but the address's organization requires single sign-on, so the session starts there instead: `sso-required` (DAWG-155).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "Unknown, expired, already taken up or withdrawn — one answer for all four.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "The invited address already has an account: sign in, then accept.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/me`.",
        "description": "The first call a portal makes, and the one that tells it whether there is a\nsession at all — so an empty `memberships` is a real answer rather than an\nerror. A person who has signed in and belongs to nothing yet is exactly who\nthe \"create an organization\" screen is for.",
        "operationId": "me",
        "responses": {
          "200": {
            "description": "Who is signed in, and the organizations they are in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "session"
        ],
        "summary": "`DELETE /v1/me`: erase the caller (DAWG-170).",
        "description": "Anonymize-and-keep: their name and address are replaced, every way of\nsigning in is removed, and they leave every organization; what they did\nstays in each organization's record under \"Former member\". See\n`db::erasure` for exactly what is kept. Refused while they are the only\nowner of an organization (`sole-owner`), and only in person: a session,\nnever an API token.",
        "operationId": "me_erase",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EraseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Erased. The session cookie is cleared; nothing can sign in as this account again."
          },
          "400": {
            "description": "`confirm` is not this account's email address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "The CSRF token is missing or wrong.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "`sole-owner`: the caller is the only owner of an organization. Make somebody else an owner, or delete the organization, first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me/export": {
      "get": {
        "tags": [
          "session"
        ],
        "summary": "`GET /v1/me/export`: everything Updawg holds about the caller, as one JSON\ndocument (DAWG-170). A data subject access request, answered without having\nto ask.",
        "operationId": "me_export",
        "responses": {
          "200": {
            "description": "A JSON download: profile, sign-in methods, sessions, and for each organization the caller is in, their membership, comments, decisions, API tokens and audited activity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonValue"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs": {
      "post": {
        "tags": [
          "organizations"
        ],
        "summary": "`POST /v1/orgs`.",
        "description": "The creator is the owner, written in the same transaction as the\norganization — otherwise there is an organization nobody can administer and\nwhich does not appear in its own creator's `GET /v1/me`.",
        "operationId": "orgs_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created. The caller becomes its owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgBody"
                }
              }
            }
          },
          "400": {
            "description": "A name or slug that will not do, or a region this API does not serve.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "That slug is taken (`slug-taken`), or the caller already owns an organization on Free (`organization-limit`): one Free organization per person, so move that one to a paid plan first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}": {
      "get": {
        "tags": [
          "organizations"
        ],
        "summary": "`GET /v1/orgs/{org}`.",
        "description": "Any member may read it. There is no `ReadFleet`-less role.\n\nAll of the work happened in the [`Member`] extractor, which is the point:\nthe organization is not looked up here because it cannot be reached without\nhaving been resolved and authorized already.",
        "operationId": "orgs_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "organizations"
        ],
        "summary": "`DELETE /v1/orgs/{org}`: delete the organization (DAWG-170).",
        "description": "Gone for everybody at once: its members lose it, its API, enrollment and\nSCIM tokens stop working and its hosts' check-ins are refused. Everything\nthat was its own is purged a week later by the nightly maintenance run.\nThe owner's alone, in person, never with an API token; refused while\nStripe is still billing it.",
        "operationId": "orgs_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Deleted. Its data is purged in seven days."
          },
          "400": {
            "description": "`confirm` is not this organization's slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not the owner, or an API token: only an owner, signed in, can.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "`subscription-active`: a paid subscription is still being billed. Cancel it in billing first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "organizations"
        ],
        "summary": "`PATCH /v1/orgs/{org}`.",
        "operationId": "orgs_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgBody"
                }
              }
            }
          },
          "400": {
            "description": "A name or slug that will not do, or a stale threshold, EOL lead time or audit retention out of range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "That slug is taken.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/advisories": {
      "get": {
        "tags": [
          "advisories"
        ],
        "summary": "`GET /v1/orgs/{org}/advisories` (DAWG-288).",
        "operationId": "advisories_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "severity",
            "in": "query",
            "description": "Repeatable: `none`, `low`, `medium`, `high`, `critical`, or `unrated` for those nobody rated.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "known_exploited",
            "in": "query",
            "description": "`true`: only advisories with a CVE in CISA's Known Exploited Vulnerabilities.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "unfixable",
            "in": "query",
            "description": "`true`: only advisories some exposed host has no available fix for.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every advisory affecting at least one host, known-exploited first, then worst, then widest.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdvisoryListBody"
                }
              }
            }
          },
          "400": {
            "description": "A filter that cannot be honoured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/advisories/{advisory_id}/hosts": {
      "get": {
        "tags": [
          "advisories"
        ],
        "summary": "`GET /v1/orgs/{org}/advisories/{advisory_id}/hosts` (DAWG-288).",
        "operationId": "advisories_hosts",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "advisory_id",
            "in": "path",
            "description": "The advisory's id, as the list gives it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The hosts it reaches, unfixable first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdvisoryHostsBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or no such advisory **here**: one that reaches none of this organization's hosts is not found, whether or not it exists elsewhere.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/agent-releases": {
      "get": {
        "tags": [
          "hosts"
        ],
        "summary": "Which agent build each release channel holds (DAWG-46), for comparing\nwith a host's `agent_version`. The channels are Updawg's and the same for\nevery organization; this is under one only so that it asks for a session\nlike everything else here. Empty until the worker has read a manifest.",
        "operationId": "hosts_agent_releases",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stable first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AgentReleaseBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/api-tokens": {
      "get": {
        "tags": [
          "api-tokens"
        ],
        "summary": "`GET /v1/orgs/{org}/api-tokens`.",
        "operationId": "api_tokens_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every token, newest first, revoked ones included.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiTokenBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or asked with an API token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "api-tokens"
        ],
        "summary": "`POST /v1/orgs/{org}/api-tokens`.",
        "operationId": "api_tokens_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Issued. ⚠️ `token` is in this response and never again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedApiTokenBody"
                }
              }
            }
          },
          "400": {
            "description": "No name, no scopes, a scope that is not one or that your role cannot grant, or an expiry in the past.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or asked with an API token. Or the plan is not Business or Enterprise: `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/api-tokens/{api_token_id}": {
      "delete": {
        "tags": [
          "api-tokens"
        ],
        "summary": "`DELETE /v1/orgs/{org}/api-tokens/{api_token_id}`.",
        "operationId": "api_tokens_revoke",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "api_token_id",
            "in": "path",
            "description": "The `atk_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked. It is refused from the next request on."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or asked with an API token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such token here, or already revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/audit-log": {
      "get": {
        "tags": [
          "audit"
        ],
        "operationId": "audit_log_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "action",
            "in": "query",
            "description": "Only this action, exactly: `host.decommissioned`.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "The `next` of the previous page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the audit log, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditPageBody"
                }
              }
            }
          },
          "400": {
            "description": "An unknown parameter, a repeated one, or a cursor that does not parse.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/audit-log/export": {
      "get": {
        "tags": [
          "audit"
        ],
        "summary": "`GET /v1/orgs/{org}/audit-log/export`.",
        "operationId": "audit_log_export",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "`csv` or `json`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "action",
            "in": "query",
            "description": "Only this action, exactly.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Entries at or after this (RFC 3339).",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "description": "Entries before this (RFC 3339).",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The log, newest first, as a download: CSV with metadata as a JSON column, or a JSON array of entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEntryBody"
                  }
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "An unknown or repeated parameter, a format other than `csv` or `json`, a time that does not parse, or more entries than one export holds — narrow `since` and `until`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/billing": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "`GET /v1/orgs/{org}/billing`.",
        "operationId": "billing_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The plan, and the subscription if there is one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Only an owner manages billing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/billing/checkout": {
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "`POST /v1/orgs/{org}/billing/checkout`.",
        "operationId": "billing_checkout",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Where to send the person to pay.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutBody"
                }
              }
            }
          },
          "400": {
            "description": "Not a plan sold through checkout: `team`, `business` or `enterprise`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Only an owner, in person, manages billing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Already subscribed (`already-subscribed`), or on Enterprise by contract with no subscription (`enterprise-contract`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment takes no payments (`billing-unavailable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/billing/plan": {
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "`POST /v1/orgs/{org}/billing/plan` (DAWG-145): move a live subscription\nbetween Team, Business and Enterprise.",
        "description": "Asks Stripe to swap the price, with the days so far billed at the old\nplan's rate; the organization's plan changes when Stripe's webhook says\nthe subscription has, as it does for a new one. Starting a subscription is\ncheckout's, and ending one the customer portal's.",
        "operationId": "billing_change_plan",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Asked of Stripe; the plan changes when its webhook arrives."
          },
          "400": {
            "description": "Not `team`, `business` or `enterprise`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Only an owner, in person, manages billing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "No live subscription to change (`no-subscription`), or already on that plan (`same-plan`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment takes no payments (`billing-unavailable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/billing/portal": {
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "`POST /v1/orgs/{org}/billing/portal` (DAWG-144, DAWG-145).",
        "description": "Stripe's customer portal, configured for Updawg: invoices to download, the\ncard to change, and cancelling, which takes effect at the end of the\nperiod. Changing plan is not offered there; the plans share one meter.",
        "operationId": "billing_portal",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Where to send the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Only an owner, in person, manages billing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "This organization has never been a Stripe customer (`no-customer`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment takes no payments (`billing-unavailable`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/billing/usage": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "`GET /v1/orgs/{org}/billing/usage` (DAWG-144).",
        "operationId": "billing_usage",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "month",
            "in": "query",
            "description": "`YYYY-MM`, UTC. This month when absent.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Active hosts per day for the month.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageBody"
                }
              }
            }
          },
          "400": {
            "description": "`month` is not `YYYY-MM`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Only an owner manages billing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/export": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/export`.",
        "operationId": "compliance_export",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataset",
            "in": "query",
            "description": "`hosts`: every host's standing now, one row each. `resolutions`: every exposure that ended in the period, with its latency.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Start of the period, for `resolutions` (RFC 3339). Default: 90 days before `until`.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "description": "End of the period, exclusive. Default: now.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "group",
            "in": "query",
            "description": "Only the hosts this group (`grp_…`) resolves to now.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A CSV download.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "An unknown or repeated parameter, a dataset other than `hosts` or `resolutions`, a bad period or group, or more resolutions than one export holds — narrow the period.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/exports": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/exports`.",
        "operationId": "compliance_exports_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The 20 most recent exports, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "compliance"
        ],
        "summary": "`POST /v1/orgs/{org}/compliance/exports`.",
        "operationId": "compliance_exports_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Queued. Poll it until `status` is `ready`, then `GET` its `download`. Audited as `compliance.export_requested`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportBody"
                }
              }
            }
          },
          "400": {
            "description": "No `kind`, or a period or group the report would refuse.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, no CSRF token, or an API token: a person asks for an export. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Three exports are already being made for this organization: `exports-busy`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has nowhere to put the files: `exports-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/exports/{export_id}": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/exports/{export_id}`.",
        "operationId": "compliance_exports_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "export_id",
            "in": "path",
            "description": "The `exp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "How the export is doing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such export here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/exports/{export_id}/download": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/exports/{export_id}/download`.",
        "operationId": "compliance_exports_download",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "export_id",
            "in": "path",
            "description": "The `exp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The file: CSV or PDF.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such export here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not ready yet, or it failed: `export-not-ready`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "410": {
            "description": "Ready once, and no longer handed out: `export-expired`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has nowhere to read the files from: `exports-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/report": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/report`.",
        "operationId": "compliance_report",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Start of the patch-latency period (RFC 3339). Default: 90 days before `until`.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "until",
            "in": "query",
            "description": "End of the period, exclusive. Default: now.",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "group",
            "in": "query",
            "description": "Only the hosts this group (`grp_…`) resolves to now.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Patch latency over the period, and the fleet's standing now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ComplianceReportBody"
                }
              }
            }
          },
          "400": {
            "description": "An unknown or repeated parameter, a time that does not parse, a period that is backwards or longer than 400 days, or a group that is not here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/compliance/targets": {
      "get": {
        "tags": [
          "compliance"
        ],
        "summary": "`GET /v1/orgs/{org}/compliance/targets`.",
        "operationId": "compliance_targets_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Days to patch a fixable exposure, per severity.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatchTargetsBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "compliance"
        ],
        "summary": "`PUT /v1/orgs/{org}/compliance/targets`.",
        "operationId": "compliance_targets_set",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTargetsBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Set. Audited as `organization.patch_targets_changed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PatchTargetsBody"
                }
              }
            }
          },
          "400": {
            "description": "A target outside 1 to 365 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token. Or the plan does not include compliance reports (Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/digest": {
      "get": {
        "tags": [
          "notifications"
        ],
        "summary": "`GET /v1/orgs/{org}/digest`.",
        "operationId": "digest_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "How often you get this organization's digest.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigestBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "notifications"
        ],
        "summary": "`PUT /v1/orgs/{org}/digest`.",
        "operationId": "digest_set",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DigestBody"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Set.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DigestBody"
                }
              }
            }
          },
          "400": {
            "description": "Not `off`, `daily` or `weekly`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "No CSRF token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/enrollment-tokens": {
      "get": {
        "tags": [
          "enrollment"
        ],
        "summary": "`GET /v1/orgs/{org}/enrollment-tokens`.",
        "operationId": "enrollment_tokens_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every token, newest first, revoked and used-up ones included — the list is also the answer to \"what could have enrolled that host\".",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TokenBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "enrollment"
        ],
        "summary": "`POST /v1/orgs/{org}/enrollment-tokens`.",
        "operationId": "enrollment_tokens_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Issued. ⚠️ `token` is in this response and never again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatedTokenBody"
                }
              }
            }
          },
          "400": {
            "description": "No name, a limit below one, an expiry in the past, or labels that are not a small map of non-empty keys.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/enrollment-tokens/{token_id}": {
      "delete": {
        "tags": [
          "enrollment"
        ],
        "summary": "`DELETE /v1/orgs/{org}/enrollment-tokens/{token_id}`.",
        "operationId": "enrollment_tokens_revoke",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "token_id",
            "in": "path",
            "description": "The `etk_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked. Hosts it already enrolled are unaffected."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such token here, or already revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/events": {
      "get": {
        "tags": [
          "events"
        ],
        "summary": "`GET /v1/orgs/{org}/events`.",
        "operationId": "events_stream",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events: `ready` first, then `change` (`{\"kind\", \"id\", \"proposal\"}`) and `resync`. Hints to refetch, never data. Ends after fifteen minutes; reconnect.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/groups": {
      "get": {
        "tags": [
          "groups"
        ],
        "summary": "`GET /v1/orgs/{org}/groups`.",
        "operationId": "groups_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every group, by name.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/HostGroupBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "groups"
        ],
        "summary": "`POST /v1/orgs/{org}/groups`.",
        "operationId": "groups_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostGroupBody"
                }
              }
            }
          },
          "400": {
            "description": "No name, or a selector that is empty or has an empty key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A group with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/groups/{group_id}": {
      "get": {
        "tags": [
          "groups"
        ],
        "summary": "`GET /v1/orgs/{org}/groups/{group_id}`.",
        "operationId": "groups_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "path",
            "description": "The `grp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The group and every host it resolves to, and why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "groups"
        ],
        "summary": "`DELETE /v1/orgs/{org}/groups/{group_id}`.",
        "operationId": "groups_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "path",
            "description": "The `grp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted. Its hosts are untouched; what pointed at it is listed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletedGroupBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "groups"
        ],
        "summary": "`PATCH /v1/orgs/{org}/groups/{group_id}`.",
        "operationId": "groups_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "path",
            "description": "The `grp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Changed. A rename lists the policies that named the old name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdatedGroupBody"
                }
              }
            }
          },
          "400": {
            "description": "An empty name, or a selector that is empty or has an empty key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A group with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/groups/{group_id}/hosts": {
      "put": {
        "tags": [
          "groups"
        ],
        "summary": "`PUT /v1/orgs/{org}/groups/{group_id}/hosts`.",
        "operationId": "groups_set_hosts",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "path",
            "description": "The `grp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetHostsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The static members are exactly these.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostsSetBody"
                }
              }
            }
          },
          "400": {
            "description": "An id that is not a host of this organization; nothing was changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts": {
      "get": {
        "tags": [
          "hosts"
        ],
        "operationId": "hosts_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Repeatable. An unknown value matches nothing rather than being refused: `host_status` is a database enum this build does not mirror, so it must not claim to know every state a host can be in.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "label",
            "in": "query",
            "description": "Repeatable, `key=value`. Several labels intersect, because a set of labels is a selector. Split on the first `=` only.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "distro",
            "in": "query",
            "description": "Repeatable.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "reboot_required",
            "in": "query",
            "description": "Repeatable: `yes`, `no` or `unknown`. Three-valued because the column is — a host that cannot answer is not a host answering no.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "`hostname` (default), `last_seen` or `security_updates`.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "The `hst_…` id of the last host on the previous page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the fleet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostListBody"
                }
              }
            }
          },
          "400": {
            "description": "A filter, sort or cursor that cannot be honoured. Refused rather than ignored: a page that looks filtered and is not is the failure worth preventing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/bulk": {
      "post": {
        "tags": [
          "hosts"
        ],
        "summary": "`POST /v1/orgs/{org}/hosts/bulk` (DAWG-78): one action on many hosts.",
        "description": "Add to a group needs `manage_group`; setting labels, refreshing,\ndecommissioning and deleting need `manage_host`; a reboot, which opens a\nproposal, needs `run_job`. Decommissioned hosts are skipped and say so,\nexcept by `decommission` (unchanged) and `delete`, which acts on nothing\nelse. At most 5,000 hosts; past that the request is refused whole.",
        "operationId": "hosts_bulk",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Done, or what a dry run would do.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkBody"
                }
              }
            }
          },
          "400": {
            "description": "Neither or both of `hosts` and `filter`; a bad filter or label; more than 5,000 hosts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "`update_agent` to a channel no agent build has been seen on yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}": {
      "get": {
        "tags": [
          "hosts"
        ],
        "operationId": "hosts_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One host, in full.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostDetailBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host, or not yours, or an id that does not parse — one answer for all three, so asking cannot be used to find out which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "hosts"
        ],
        "summary": "`DELETE /v1/orgs/{org}/hosts/{host_id}` — decommission (DAWG-285).",
        "operationId": "hosts_decommission",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Decommissioned, or already was. The gateway refuses the host from its next request; the row stays, so its history does too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecommissionedBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "hosts"
        ],
        "summary": "`PATCH /v1/orgs/{org}/hosts/{host_id}` (DAWG-285).",
        "operationId": "hosts_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateHostRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Changed; the host as it now is. A label change queues the host for evaluation, so its proposals and label groups catch up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostDetailBody"
                }
              }
            }
          },
          "400": {
            "description": "Too many labels, an empty key, or a display name or notes that are too long.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}/events": {
      "get": {
        "tags": [
          "hosts"
        ],
        "summary": "The host's timeline, newest first: jobs finishing, refused or expiring, and\nthe host going stale and coming back. What a person did *to* the host —\nrelabelling, decommissioning — is the audit log's, filtered by target.",
        "operationId": "hosts_events",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "The `next` of the previous page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the timeline, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HostEventPageBody"
                }
              }
            }
          },
          "400": {
            "description": "An unknown parameter, a repeated one, or a cursor that does not parse.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}/exposures": {
      "get": {
        "tags": [
          "hosts"
        ],
        "summary": "`GET /v1/orgs/{org}/hosts/{host_id}/exposures` (DAWG-212).",
        "description": "The advisories this host's **installed** packages are affected by, whether\nor not an update fixes them. Unfixable first: those are the ones nothing\nin the update list will ever show.",
        "operationId": "hosts_exposures",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every exposure, unfixable first, then worst first. Empty for a host that is up to date — or one not evaluated since exposures existed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExposureListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}/purge": {
      "post": {
        "tags": [
          "hosts"
        ],
        "summary": "`POST /v1/orgs/{org}/hosts/{host_id}/purge` — delete a decommissioned host (DAWG-286).",
        "operationId": "hosts_purge",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted, with its packages, jobs, its rows in every proposal, its timeline and heartbeats. Cannot be undone; the audit log keeps a `host.deleted` entry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletedBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not decommissioned. Decommission it first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}/readiness": {
      "get": {
        "tags": [
          "hosts"
        ],
        "summary": "Whether this host's third-party repositories publish the releases it could\nupgrade to (DAWG-149), from the daily probe. One entry per repository and\ntarget release; empty until the probe has run, for a host with no\nthird-party repositories, or one whose agent is older than protocol 0.6.",
        "operationId": "hosts_readiness",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "What each third-party repository has for each target release.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadinessListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/hosts/{host_id}/unfixed": {
      "get": {
        "tags": [
          "hosts"
        ],
        "summary": "The vulnerabilities this host is affected by that **nothing fixes in its\nrelease** (DAWG-212 part 2): no advisory will ever name them, so neither\nthe update list nor [`exposures`] can. Debian only, from the security\ntracker; worst first, then longest standing.",
        "operationId": "hosts_unfixed",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host_id",
            "in": "path",
            "description": "The `hst_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every unfixed vulnerability affecting the host. Empty for a host that has none — or whose agent is too old to report source packages, or that is not Debian.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnfixedListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such host, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/invitations": {
      "get": {
        "tags": [
          "organizations"
        ],
        "summary": "`GET /v1/orgs/{org}/invitations`.",
        "description": "Administration, unlike the members list: an outstanding invitation is a\nstatement about somebody who is *not* here, and the addresses in it were\ntyped by an administrator rather than volunteered by their owners.",
        "operationId": "invitations_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Outstanding invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "organizations"
        ],
        "summary": "`POST /v1/orgs/{org}/invitations`.",
        "operationId": "invitations_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Invited. ⚠️ The token is in the email and is **not** in this response.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationBody"
                }
              }
            }
          },
          "400": {
            "description": "Not an address, or not a role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "That person is already in this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/invitations/{invitation_id}": {
      "delete": {
        "tags": [
          "organizations"
        ],
        "summary": "`DELETE /v1/orgs/{org}/invitations/{id}`.",
        "operationId": "invitations_revoke",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "invitation_id",
            "in": "path",
            "description": "The `inv_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such invitation here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/jobs/unsigned": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/jobs/unsigned`.",
        "operationId": "jobs_unsigned",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every job waiting for your organization's signature, oldest first. Empty unless the organization holds its own signing key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnsignedJobListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/jobs/{job_id}/logs": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/jobs/{job_id}/logs`.",
        "operationId": "job_logs",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "job_id",
            "in": "path",
            "description": "The `job_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "Only lines after this sequence number.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The lines after `after`, in order. Empty while nothing has been sent.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such job here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/jobs/{job_id}/signature": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/jobs/{job_id}/signature`.",
        "description": "The signature is checked here, against the key the job names, so that a\nwrong key or a signature over the wrong bytes fails now rather than on\nevery host. It protects nothing by itself — each host verifies against the\nkey it pinned — and that is the point of the design.",
        "operationId": "jobs_sign",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "job_id",
            "in": "path",
            "description": "The `job_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignatureRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Accepted: the job is queued for its host.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignedJobBody"
                }
              }
            }
          },
          "400": {
            "description": "No signature, or one that does not verify under the key the job names over the job's signing bytes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such job here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "The job is not waiting for a signature — signed already, expired, or cancelled by a halt — or the key it names has been retired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/members": {
      "get": {
        "tags": [
          "organizations"
        ],
        "summary": "`GET /v1/orgs/{org}/members`.",
        "description": "Readable by every member, including a viewer: knowing who else is in the\norganization you are in is not privileged, and hiding it would mean a viewer\ncannot work out who to ask for something.",
        "operationId": "orgs_members",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Everybody in it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MemberBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/members/{user_id}": {
      "delete": {
        "tags": [
          "organizations"
        ],
        "summary": "`DELETE /v1/orgs/{org}/members/{user_id}`.",
        "operationId": "orgs_remove_member",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "description": "The `usr_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such member here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Refused because it would leave the organization with no owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "organizations"
        ],
        "summary": "`PATCH /v1/orgs/{org}/members/{user_id}`.",
        "operationId": "orgs_set_role",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "description": "The `usr_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RoleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Applied: the member, at their role now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberBody"
                }
              }
            }
          },
          "400": {
            "description": "A body with no `role`, or one that is not a role (DAWG-246).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such member here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Refused because it would leave the organization with no owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-channels": {
      "get": {
        "tags": [
          "notifications"
        ],
        "summary": "`GET /v1/orgs/{org}/notification-channels`.",
        "operationId": "notification_channels_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every channel, by name. No configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ChannelBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "notifications"
        ],
        "summary": "`POST /v1/orgs/{org}/notification-channels`.",
        "operationId": "notification_channels_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateChannelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Saved, encrypted. The configuration is not in this response or any other; a webhook's `signing_secret` is, and only here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedChannelBody"
                }
              }
            }
          },
          "400": {
            "description": "No name, an unknown kind, a configuration that kind does not accept, or a webhook `secret` (Updawg makes it).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include this kind of channel (Slack, Teams, ntfy and PagerDuty are Team; webhooks Business): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A channel with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment cannot encrypt channel credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-channels/{channel_id}": {
      "delete": {
        "tags": [
          "notifications"
        ],
        "summary": "`DELETE /v1/orgs/{org}/notification-channels/{channel_id}`.",
        "operationId": "notification_channels_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel_id",
            "in": "path",
            "description": "The `nch_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted, with the rules that sent to it and its delivery log."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such channel here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "notifications"
        ],
        "summary": "`PATCH /v1/orgs/{org}/notification-channels/{channel_id}`.",
        "operationId": "notification_channels_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel_id",
            "in": "path",
            "description": "The `nch_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateChannelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Changed. Replacing a webhook's configuration makes it a new `signing_secret`, returned here and only here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedChannelBody"
                }
              }
            }
          },
          "400": {
            "description": "An empty name, a configuration the channel's kind does not accept, or a webhook `secret`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such channel here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A channel with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment cannot encrypt channel credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-channels/{channel_id}/deliveries": {
      "get": {
        "tags": [
          "notifications"
        ],
        "summary": "`GET /v1/orgs/{org}/notification-channels/{channel_id}/deliveries`.",
        "operationId": "notification_channels_deliveries",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel_id",
            "in": "path",
            "description": "The `nch_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The channel's 50 most recent deliveries, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DeliveryBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such channel here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-channels/{channel_id}/deliveries/{delivery_id}/replay": {
      "post": {
        "tags": [
          "notifications"
        ],
        "summary": "`POST /v1/orgs/{org}/notification-channels/{channel_id}/deliveries/{delivery_id}/replay`.",
        "operationId": "notification_channels_replay",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel_id",
            "in": "path",
            "description": "The `nch_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "delivery_id",
            "in": "path",
            "description": "The delivery's id, from the log.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Queued as a new delivery of the same message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReplayBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such delivery on this channel, or it is still being tried.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-channels/{channel_id}/test": {
      "post": {
        "tags": [
          "notifications"
        ],
        "summary": "`POST /v1/orgs/{org}/notification-channels/{channel_id}/test`.",
        "operationId": "notification_channels_test",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel_id",
            "in": "path",
            "description": "The `nch_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tried, and whether it arrived. Recorded in the channel's delivery log either way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestResultBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such channel here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment cannot decrypt channel credentials.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-rules": {
      "get": {
        "tags": [
          "notifications"
        ],
        "summary": "`GET /v1/orgs/{org}/notification-rules`.",
        "operationId": "notification_rules_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every rule, by name.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RuleBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "notifications"
        ],
        "summary": "`POST /v1/orgs/{org}/notification-rules`.",
        "operationId": "notification_rules_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRuleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Saved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RuleBody"
                }
              }
            }
          },
          "400": {
            "description": "No name, no event type or one that does not exist, a channel id that is not one of this organization's, or a filter with a field that does not exist.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A rule with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/notification-rules/{rule_id}": {
      "delete": {
        "tags": [
          "notifications"
        ],
        "summary": "`DELETE /v1/orgs/{org}/notification-rules/{rule_id}`.",
        "operationId": "notification_rules_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rule_id",
            "in": "path",
            "description": "The `nru_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. Its channels are unaffected."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such rule here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "notifications"
        ],
        "summary": "`PATCH /v1/orgs/{org}/notification-rules/{rule_id}`.",
        "operationId": "notification_rules_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rule_id",
            "in": "path",
            "description": "The `nru_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRuleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Changed. `channel_ids`, when given, replaces the list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RuleBody"
                }
              }
            }
          },
          "400": {
            "description": "As for creating one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such rule here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A rule with that name exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies": {
      "get": {
        "tags": [
          "policies"
        ],
        "summary": "`GET /v1/orgs/{org}/policies`.",
        "operationId": "policies_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every live policy. ⚠️ Without its YAML — a page showing forty policies does not render forty documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Summary"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "policies"
        ],
        "summary": "`POST /v1/orgs/{org}/policies`.",
        "operationId": "policies_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created at version 1.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Detail"
                }
              }
            }
          },
          "400": {
            "description": "The document does not compile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or a plan that does not include a feature it uses: `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A live policy already has that name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies/preview": {
      "post": {
        "tags": [
          "policies"
        ],
        "summary": "`POST /v1/orgs/{org}/policies/preview`.",
        "description": "What saving this document would do to the fleet as it is right now. **Reads\nand evaluates; writes nothing.**\n\nSend `replaces` when previewing an edit: a proposal's identity begins with\nits policy's id, so without it an edit previews as a new policy and every\nproposal appears to close and reopen. Both sides of the diff are evaluated\nnow, over the same hosts — not compared with the proposals already open.",
        "operationId": "policies_preview",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "What saving this would do: which proposals it would open, and — the half nobody asks for — which updates it would stop covering.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewBody"
                }
              }
            }
          },
          "400": {
            "description": "The document does not compile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Another live policy already holds that name — which is what saving it would answer, and therefore what previewing it has to.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies/preview/context": {
      "get": {
        "tags": [
          "policies"
        ],
        "summary": "`GET /v1/orgs/{org}/policies/preview/context`.",
        "description": "Everything `preview` reads besides the document, so that the portal can run\nthe same engine in the browser on every keystroke instead of asking this\nendpoint each time (DAWG-93). Capped at the same number of hosts, oldest\nfirst, so the two answer about the same fleet.",
        "operationId": "policies_preview_context",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The policies in force and the fleet a preview evaluates. ⚠️ Check `engine` against the engine you run it with: a different version may decide differently, and the preview endpoint is the answer then.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewContext"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies/validate": {
      "post": {
        "tags": [
          "policies"
        ],
        "summary": "`POST /v1/orgs/{org}/policies/validate`.",
        "description": "⚠️ **A policy that does not parse is a 200.** The endpoint's job is to\nreport whether a document is valid, and \"it is not\" is that job done — a\n400 would mean *the request* was wrong, and an editor calling this on every\nkeystroke would spend most of its life looking at errors that are not\nerrors. The 400s here are a missing or oversized `yaml`, which are wrong\nrequests.\n\nValidating means **compiling**, not reading fields off the parsed document.\nIt is the same call `create` and `update` make, so a document this accepts\nis a document those will store rather than one that merely looks similar.",
        "operationId": "policies_validate",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "⚠️ **200 even for a document that does not parse.** It was asked whether the document is valid and it answers; a 400 would mean the *request* was wrong, and an editor calling this per keystroke would spend its life looking at errors that are not errors. Saving the same document is a 400.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Validation"
                }
              }
            }
          },
          "400": {
            "description": "⚠️ Not *\"the document is invalid\"* — that is the 200 above. A missing or oversized `yaml`, which is a wrong request rather than a wrong policy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies/{policy_id}": {
      "get": {
        "tags": [
          "policies"
        ],
        "summary": "`GET /v1/orgs/{org}/policies/{policy_id}`, optionally `?version=2`.",
        "operationId": "policies_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "description": "The `pol_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "query",
            "description": "An older version. Reading one and PUTting it back is how a rollback is done, and the history then shows the rollback as a new version.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The policy, at the version asked for.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Detail"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such policy, or deleted, or no such version — one answer for all three, so asking cannot find out which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "policies"
        ],
        "summary": "`PUT /v1/orgs/{org}/policies/{policy_id}`.",
        "operationId": "policies_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "description": "The `pol_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PolicyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "A new version, and it becomes current.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Detail"
                }
              }
            }
          },
          "400": {
            "description": "The document does not compile.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or a plan that does not include a feature it uses: `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such policy here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "A live policy already has that name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "policies"
        ],
        "summary": "`DELETE /v1/orgs/{org}/policies/{policy_id}`.",
        "description": "A soft delete. The policy stops evaluating and stops appearing; its versions\nstay, so every proposal it ever produced keeps its reason. See migration 29.",
        "operationId": "policies_remove",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "description": "The `pol_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted, softly. A hard delete would destroy the answer to why an existing proposal exists."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such policy here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/policies/{policy_id}/versions": {
      "get": {
        "tags": [
          "policies"
        ],
        "summary": "`GET /v1/orgs/{org}/policies/{policy_id}/versions`.",
        "description": "Newest first, each entry carrying what that version *changed* rather than\nwhat it contained. A history page is a list of changes; the text of any one\nversion is a `?version=` away.",
        "operationId": "policies_versions",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policy_id",
            "in": "path",
            "description": "The `pol_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Append-only history, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HistoryBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such policy here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals`.",
        "description": "Newest first, `?status=` repeatable, keyset-paginated on `?after=`.\n\n# No status means every status\n\nIncluding one this build does not recognise. The temptation is to default an\ninbox to the open ones — and a default that hides rows is a default that\nmakes a proposal somebody is waiting on invisible without saying so. The\nportal asks for what it wants to show; the API does not decide on its behalf.\n\n# ⚠️ Why the query is a list of pairs and not a struct\n\n`Query<T>` deserialises with `serde_urlencoded`, which **cannot** put a\nrepeated key into a `Vec`. `?status=open&status=snoozed` against a\n`Vec<String>` field does not collect two values — it fails, and it fails\nwith axum's own plain-text 400, which carries no `type` for a portal to\nbranch on and is a different shape from every other refusal this API makes.\nThat is DAWG-246's problem arriving by a second route.\n\n`Vec<(String, String)>` is what `serde_urlencoded` does support, so the\npairs are read and interpreted here. It buys one more thing worth having:\nan **unknown** parameter can be refused. `?staus=open` silently returning\neverything is the same failure as an unparseable status silently returning\neverything, and both are a list that is quietly not what was asked for.",
        "operationId": "proposals_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Repeatable. Omitted means **every** status, including one this build does not recognise — a default that hides rows hides the proposal somebody is waiting on.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "after",
            "in": "query",
            "description": "The `prp_…` id of the last proposal on the previous page.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "policy",
            "in": "query",
            "description": "Only proposals this policy made, as `pol_…`; `none` for those no policy made. One section of `GET …/proposals/grouped?by=policy` (DAWG-303).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "query",
            "description": "Only proposals targeting a host in this group, as `grp_…`, or made for it; `none` for those in no group. A proposal across two groups is in both.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalListBody"
                }
              }
            }
          },
          "400": {
            "description": "An unknown status, an unknown parameter, a malformed `policy` or `group`, or a cursor naming nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/grouped": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals/grouped?by=policy|group` (DAWG-303).",
        "description": "The sections of a grouped inbox and how many proposals each holds, under\nthe same `?status=` as the list. Each section opens with the list's\n`?policy=` or `?group=` — `none` for the section without one — so a section\npages like the inbox does rather than arriving whole.",
        "operationId": "proposals_grouped",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "by",
            "in": "query",
            "description": "`policy` or `group`.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Repeatable, as on the list. Omitted means every status.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Biggest section first; the one for proposals with no policy or group last.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupedBody"
                }
              }
            }
          },
          "400": {
            "description": "No `by`, an unknown one, an unknown status or parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals/{proposal_id}`.",
        "operationId": "proposals_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The proposal in full. ⚠️ `changes` is grouped by package **and both versions**, not one entry per host per package — a fleet on two starting versions is two changes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalDetailBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/approve": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/approve`.",
        "description": "Takes no body. The design document has this endpoint carrying an optional\nschedule and rollout override; the rollout override belongs to epic 09 and\nhas nowhere to go today, and inventing a field that is accepted and ignored\nis worse than not having one.\n\nThe *schedule* half arrived with DAWG-92 and is not a field either, because\nit is not the approver's to choose: a proposal whose rule says\n`apply: asap_in_window` and whose window is shut comes back `scheduled`,\nwith `scheduled_for` saying when it opens. Approving is agreeing to the\nchange, not to the hour.",
        "operationId": "proposals_approve",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Where it is now. `scheduled` with a `scheduled_for` when the rule wants a maintenance window — approving is agreeing to the change, not to the hour.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalState"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Already approved by you, no longer yours to decide, or its current preflight fails on a host (`preflight-failed`, DAWG-153), or it is a release upgrade no agent carries out yet: anything but Debian (`not-executable`), or the organization is a Free one past its week over the Free allowance (`over-free-allowance`, DAWG-295).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/cancel": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/cancel` (DAWG-100).",
        "description": "Abandon a halted rollout: the proposal goes `failed`, and anything still\nqueued is cancelled.",
        "operationId": "proposals_cancel",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled; the proposal is `failed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoppedBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not halted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/comments": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals/{proposal_id}/comments`.",
        "description": "Oldest first. The most recent [`db::comments::PAGE`] of them, with `total`\nsaying how many there are — see that constant for why it is the recent end\nrather than the first page.",
        "operationId": "comments_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The thread, oldest first — the most recent page of it, with `total` saying how many there are.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/comments`.",
        "operationId": "comments_create",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Written. `mentions` lists the addresses that resolved to members of **this** organization; one belonging to somebody elsewhere and one belonging to nobody produce the same answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentBody"
                }
              }
            }
          },
          "400": {
            "description": "An empty body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's, or not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/halt": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/halt` (DAWG-100).",
        "description": "Stop a rollout: the proposal goes `halted` and every job no host has\npicked up yet is cancelled. Jobs a host already holds are **not**: an\nagent that holds a verified job runs it, so they finish and report as\nnormal, and `still_out` says how many there are.",
        "operationId": "proposals_halt",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Halted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoppedBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not rolling out.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/jobs": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals/{proposal_id}/jobs`.",
        "operationId": "jobs_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every job the proposal became, by hostname. Empty until it is approved and dispatched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobListBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/preflight": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "A proposal's preflight: whether one can be asked for, who asked last, and\nwhat each host it targets found (DAWG-153).",
        "operationId": "proposals_preflight_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The preflight, asked for or not.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreflightBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "Ask every host a proposal targets whether it can take the change\n(DAWG-153).",
        "description": "Each is sent a signed `run_preflight` job naming exactly the proposal's\npackages. The agent changes nothing: it looks at disk space, held\npackages, edited configuration files, DKMS modules, snapshots and reboots,\nand answers `pass`, `warn` or `fail` for each. For a proposal that has not\nstarted changing hosts (open, snoozed, scheduled) or has halted. Asking\nagain replaces the last results once they are all in.",
        "operationId": "proposals_preflight",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Asked for; the jobs are being signed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreflightBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not possible now; `detail` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/reject": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/reject`.",
        "operationId": "proposals_reject",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RejectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalState"
                }
              }
            }
          },
          "400": {
            "description": "A reason is required and must not be blank.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "No longer yours to decide.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/resume": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/resume` (DAWG-110).",
        "description": "Carry a halted rollout on, retrying what failed: every job that stopped\nit is signed again for its host, and a staged rollout picks up the stage\nit halted in.",
        "operationId": "proposals_resume",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rolling out again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResumedBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not halted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/rollback": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "A proposal's rollback: whether one can be asked for, and exactly what it\ndoes to each host (DAWG-120). What the portal's confirmation says.",
        "operationId": "proposals_rollback_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The rollback, asked for or not.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RollbackBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "Roll a halted, merged or failed proposal back (DAWG-120).",
        "description": "Every host it changed goes back to the snapshot it took before the change:\n**the whole filesystem**, so configuration edited and logs written since\ngo back too. Hosts without such a snapshot are skipped, and the answer\nsays which and why. One person who may approve may ask; the signer checks\nthat they still may when it signs. Once asked, the proposal cannot be\nresumed.",
        "operationId": "proposals_rollback",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Asked for; the jobs are being signed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RollbackBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not possible now, or already asked for; `detail` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/rollout": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/proposals/{proposal_id}/rollout`.",
        "operationId": "proposals_rollout",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The stages and their hosts. `strategy` is null, with no stages, when the rule named no rollout and every host goes at once.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RolloutPlanBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/proposals/{proposal_id}/snooze": {
      "post": {
        "tags": [
          "proposals"
        ],
        "summary": "`POST /v1/orgs/{org}/proposals/{proposal_id}/snooze`.",
        "operationId": "proposals_snooze",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "proposal_id",
            "in": "path",
            "description": "The `prp_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SnoozeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Snoozed until the time given.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalState"
                }
              }
            }
          },
          "400": {
            "description": "A time in the past.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "An operator's, deliberately: taking a proposal off the dashboard for a month is the same power as rejecting it without the audit trail saying no.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such proposal here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "No longer yours to decide.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/release-upgrades": {
      "post": {
        "tags": [
          "releases"
        ],
        "summary": "Plan a release upgrade (DAWG-153): open a `dist_upgrade` proposal for\nevery host on `from` — or those in one group — to `to`.",
        "description": "It names no packages. Run its preflight to check each host against the\ntarget: disk, held packages, edited configuration, DKMS, snapshots, and\nwhether each third-party repository publishes the target. It cannot be\napproved yet: no agent executes a release upgrade.",
        "operationId": "releases_plan_upgrade",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanUpgradeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Planned.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlannedBody"
                }
              }
            }
          },
          "400": {
            "description": "No such release, or `to` is not one `from` can be upgraded to.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such group here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "The same release, target and group are planned already (`already-planned`, `detail` names it), or no host runs the release (`no-hosts`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/releases": {
      "get": {
        "tags": [
          "releases"
        ],
        "summary": "`GET /v1/orgs/{org}/releases`.",
        "operationId": "releases_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every release the fleet runs, what it can move to, and the plans to.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReleasesBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/rollouts": {
      "get": {
        "tags": [
          "proposals"
        ],
        "summary": "`GET /v1/orgs/{org}/rollouts`.",
        "description": "Newest first, at most 200. Query pairs rather than a struct, and an\nunknown parameter or status refused, for the reasons `proposals::list`\ngives: a list quietly not filtered as asked is the failure worth refusing.",
        "operationId": "rollouts_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Repeatable. Omitted means every status.",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first, at most 200.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RolloutListBody"
                }
              }
            }
          },
          "400": {
            "description": "An unknown status or parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/scim/token": {
      "get": {
        "tags": [
          "sso"
        ],
        "summary": "`GET /v1/orgs/{org}/scim/token`.",
        "operationId": "scim_status",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whether a SCIM token is issued, and where the provider sends requests (DAWG-156).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScimStatusBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include SCIM (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "sso"
        ],
        "summary": "`POST /v1/orgs/{org}/scim/token`.",
        "operationId": "scim_issue",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "A new token, shown once. Any earlier one stops working. Audited as `scim.token_issued`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScimTokenBody"
                }
              }
            }
          },
          "400": {
            "description": "No single sign-on connection yet: SCIM's roles and domains are the connection's.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token. Or the plan does not include SCIM (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "sso"
        ],
        "summary": "`DELETE /v1/orgs/{org}/scim/token`.",
        "operationId": "scim_revoke",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked: the provider's next request is refused. Members stay as they are."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization or token, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/signing-keys": {
      "get": {
        "tags": [
          "signing-keys"
        ],
        "summary": "`GET /v1/orgs/{org}/signing-keys`.",
        "operationId": "signing_keys_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every key, newest first. Retired ones included: an agent that pinned one is told it is retired rather than told nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SigningKeyBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/signing-keys/endorse": {
      "post": {
        "tags": [
          "signing-keys"
        ],
        "summary": "`POST /v1/orgs/{org}/signing-keys/endorse`.",
        "operationId": "signing_keys_endorse",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EndorseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Your next key is the active one, endorsed by the one before, which is retiring. Hosts adopt it at their next certificate renewal; jobs wait for it in `updawgctl sign` from now on. Retire the previous key once every host pins the new one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndorsedBody"
                }
              }
            }
          },
          "400": {
            "description": "No endorsement or proof, or one that does not hold: wrong organization, too old, about different keys, or a signature that does not verify under your active key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include customer-held signing keys (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "No active key, Updawg holds it (rotate it, or hand over to yours), the endorsement is by a key that is not the active one, or the next key is already one of the organization's.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/signing-keys/hand-over": {
      "post": {
        "tags": [
          "signing-keys"
        ],
        "summary": "`POST /v1/orgs/{org}/signing-keys/hand-over`.",
        "operationId": "signing_keys_hand_over",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HandOverRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Queued. Updawg's current key endorses yours, and yours becomes the active key; the list shows it when it lands. From then on every job waits for `updawgctl sign`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotationQueuedBody"
                }
              }
            }
          },
          "400": {
            "description": "No proof, or one that does not prove the key: wrong organization, too old, not the key endorsing itself, or a signature that does not verify.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include customer-held signing keys (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "No key to endorse yours with, the organization holds its own key already, this key is already one of the organization's, or an earlier hand-over failed and is waiting for an operator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/signing-keys/retire": {
      "post": {
        "tags": [
          "signing-keys"
        ],
        "summary": "`POST /v1/orgs/{org}/signing-keys/retire`.",
        "operationId": "signing_keys_retire",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RetireRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Retired. No job is signed with it again, and hosts refuse anything it signed once they next renew — which they do within minutes of a rotation. A host that has not renewed since holds no key that can sign its jobs until it does: check each key's `hosts_pinned` first. After a hand-over, Updawg is never asked to sign for this organization again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RetiredBody"
                }
              }
            }
          },
          "400": {
            "description": "`key` is missing or not a signing key id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization or key, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Not a key still retiring while another is active: the active key, or one already retired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/signing-keys/rotate": {
      "post": {
        "tags": [
          "signing-keys"
        ],
        "summary": "`POST /v1/orgs/{org}/signing-keys/rotate`.",
        "operationId": "signing_keys_rotate",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Queued. The signer makes the new key and the outgoing one endorses it; the list shows it when it lands. Asking again before then is the same request, not a second rotation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotationQueuedBody"
                }
              }
            }
          },
          "400": {
            "description": "`from` is not a signing key id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "Nothing to rotate, a customer-held key, `from` is no longer the active key, or an earlier rotation from this key failed and is waiting for an operator.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/install": {
      "post": {
        "tags": [
          "slack"
        ],
        "summary": "`POST /v1/orgs/{org}/slack/install`.",
        "operationId": "slack_install",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Where to send the browser. Slack sends it back to `GET /v1/integrations/slack/callback`, which sends it on to the portal's settings with `slack=installed` or `slack=failed&reason=…`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackInstallBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or an API token (installing is a person's act), or the plan does not include chat notifications: `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no Slack app: `slack-unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/installations": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/orgs/{org}/slack/installations`.",
        "operationId": "slack_installations_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every workspace the app is installed in for this organization.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SlackInstallationBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/installations/{installation_id}": {
      "delete": {
        "tags": [
          "slack"
        ],
        "summary": "`DELETE /v1/orgs/{org}/slack/installations/{installation_id}`.",
        "operationId": "slack_installations_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "installation_id",
            "in": "path",
            "description": "The `sli_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Uninstalled: the token is given back to Slack, and every link made through it is gone. Channels in that workspace stay, and fail saying so, until they are deleted or the app is installed again."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such installation here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/installations/{installation_id}/channels": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/orgs/{org}/slack/installations/{installation_id}/channels`.",
        "operationId": "slack_installation_channels",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "installation_id",
            "in": "path",
            "description": "The `sli_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The workspace's public channels that are not archived, by name: at most 2,000, and `truncated` when there are more.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackChannelsBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or the plan does not include chat notifications: `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such installation here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "The app's token cannot list channels: removed in Slack, or installed before the app asked for `channels:read`. `slack-reinstall-needed`; installing again fixes it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no Slack app (`slack-unavailable`), or Slack is rate limiting it (`slack-busy`, with `Retry-After`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/link-requests/{link_token}": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/orgs/{org}/slack/link-requests/{link_token}`.",
        "operationId": "slack_link_request_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "link_token",
            "in": "path",
            "description": "The token from the link Slack showed.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whose Slack account would be linked, in which workspace. Show both before asking anybody to confirm.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackLinkRequestBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "An API token without the `read` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such offer here, or it was used or is more than ten minutes old.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "slack"
        ],
        "summary": "`POST /v1/orgs/{org}/slack/link-requests/{link_token}`.",
        "operationId": "slack_link_request_confirm",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "link_token",
            "in": "path",
            "description": "The token from the link Slack showed.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Linked: that Slack user acts as the caller from now on, replacing any link they had.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackLinkBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "An API token: linking is a person's act.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such offer here, or it was used or is more than ten minutes old.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/links": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/orgs/{org}/slack/links`.",
        "operationId": "slack_links_list",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every link, for an administrator; the caller's own, for anybody else.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SlackLinkBody"
                  }
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "An API token without the `read` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/links/{link_id}": {
      "delete": {
        "tags": [
          "slack"
        ],
        "summary": "`DELETE /v1/orgs/{org}/slack/links/{link_id}`.",
        "operationId": "slack_links_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "link_id",
            "in": "path",
            "description": "The `slk_…` id.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Unlinked: that Slack user's clicks act as nobody until they link again."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "An API token: unlinking is a person's act.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such link here, or — for anybody but an administrator — not the caller's.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/slack/settings": {
      "get": {
        "tags": [
          "slack"
        ],
        "summary": "`GET /v1/orgs/{org}/slack/settings`.",
        "operationId": "slack_settings_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The organization's Slack settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackSettingsBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "slack"
        ],
        "summary": "`PATCH /v1/orgs/{org}/slack/settings`.",
        "operationId": "slack_settings_update",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SlackSettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Changed, and audited as `slack.settings_changed`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackSettingsBody"
                }
              }
            }
          },
          "400": {
            "description": "Not a settings document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or an API token: who may approve from where is a person's decision.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours — one answer for both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/sso": {
      "get": {
        "tags": [
          "sso"
        ],
        "summary": "`GET /v1/orgs/{org}/sso`.",
        "operationId": "sso_show",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The connection (never its secret) and the claimed domains.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role. Or the plan does not include single sign-on (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "sso"
        ],
        "summary": "`PUT /v1/orgs/{org}/sso`.",
        "operationId": "sso_save",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SsoConnectionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Saved. The issuer's discovery document was read to check it. Audited as `sso.connection_saved`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoBody"
                }
              }
            }
          },
          "400": {
            "description": "An issuer that is not https:// or whose discovery document cannot be read or names another issuer; no client secret on a first save; a mapping to an unknown role or to owner; enforced without enabled or without a verified domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token. Or the plan does not include single sign-on (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "The key secrets are encrypted under is not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "sso"
        ],
        "summary": "`DELETE /v1/orgs/{org}/sso`.",
        "operationId": "sso_delete",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed; members sign in some other way from now on. Allowed on any plan, so a downgraded organization can tidy up."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization or connection, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/sso/domains": {
      "post": {
        "tags": [
          "sso"
        ],
        "summary": "`POST /v1/orgs/{org}/sso/domains`.",
        "operationId": "sso_domain_claim",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SsoDomainRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Claimed, not yet verified: publish the TXT record it names, then verify. Claiming one already claimed here answers the same claim.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoDomainBody"
                }
              }
            }
          },
          "400": {
            "description": "Not a domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token. Or the plan does not include single sign-on (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/sso/domains/{domain}": {
      "delete": {
        "tags": [
          "sso"
        ],
        "summary": "`DELETE /v1/orgs/{org}/sso/domains/{domain}`.",
        "operationId": "sso_domain_release",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "domain",
            "in": "path",
            "description": "A domain claimed here.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Released. Addresses at it no longer sign in through the connection."
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization or claim, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/orgs/{org}/sso/domains/{domain}/verify": {
      "post": {
        "tags": [
          "sso"
        ],
        "summary": "`POST /v1/orgs/{org}/sso/domains/{domain}/verify`.",
        "operationId": "sso_domain_verify",
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "description": "Organization slug.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "domain",
            "in": "path",
            "description": "A domain claimed here.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The TXT record was found: verified. Audited as `sso.domain_verified`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoDomainBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Not permitted for this role, or no CSRF token. Or the plan does not include single sign-on (Enterprise): `plan-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "No such organization or claim, or not yours.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "409": {
            "description": "The record is not there yet (`txt-not-found`; DNS can take a while), or another organization has verified this domain (`domain-taken`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "421": {
            "description": "The organization's data is in another region (`wrong-region`, DAWG-159). `detail` names that region's API; send the request there.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "429": {
            "description": "Over the organization's request limit. `Retry-After` says when to try again; `RateLimit-Limit` is the burst.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "DNS could not be asked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/regions/{region}/token": {
      "post": {
        "tags": [
          "session"
        ],
        "summary": "`POST /v1/regions/{region}/token`.",
        "operationId": "regions_token",
        "parameters": [
          {
            "name": "region",
            "in": "path",
            "description": "`us`, or another region this deployment knows of.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A token for that region's API, for about ten minutes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegionToken"
                }
              }
            }
          },
          "400": {
            "description": "This API's own region: use the session you have.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "401": {
            "description": "No session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "403": {
            "description": "Refused: no CSRF token or not this session's.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "404": {
            "description": "Not a region this deployment knows of.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment does not issue region tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stripe/webhook": {
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "`POST /v1/stripe/webhook`.",
        "description": "Unauthenticated in the session sense; authenticated by the\n`Stripe-Signature` header over the exact bytes received. An event handled\nbefore is acknowledged and not handled again, and one that is not about an\nUpdawg subscription — this Stripe account also bills another business — is\nacknowledged and ignored.",
        "operationId": "stripe_webhook",
        "requestBody": {
          "description": "A Stripe event, byte for byte as Stripe signed it.",
          "content": {
            "application/json": {
              "schema": {
                "type": "string"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Received; handled now, before, or not ours."
          },
          "400": {
            "description": "Not a Stripe event, or not signed by Stripe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          },
          "503": {
            "description": "This deployment has no webhook secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemBody"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AcceptRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          }
        }
      },
      "Action": {
        "type": "string",
        "description": "What a rule decided should happen.",
        "enum": [
          "propose",
          "auto_merge",
          "ignore"
        ]
      },
      "AdvisoryBody": {
        "type": "object",
        "required": [
          "id",
          "source",
          "external_id",
          "title",
          "cves",
          "known_exploited"
        ],
        "properties": {
          "cves": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "external_id": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "known_exploited": {
            "type": "boolean",
            "description": "A CVE it lists is on CISA's Known Exploited Vulnerabilities list\n(DAWG-72)."
          },
          "severity": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AdvisoryHostsBody": {
        "type": "object",
        "required": [
          "hosts"
        ],
        "properties": {
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExposedHostBody"
            }
          }
        }
      },
      "AdvisoryListBody": {
        "type": "object",
        "required": [
          "total",
          "advisories"
        ],
        "properties": {
          "advisories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetAdvisoryBody"
            }
          },
          "total": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "AgentInstallBody": {
        "type": "object",
        "required": [
          "method"
        ],
        "properties": {
          "channel": {
            "type": [
              "string",
              "null"
            ],
            "description": "The channel the package repository follows, e.g. `stable`. Absent for\na binary install, which can take a build from any channel."
          },
          "method": {
            "type": "string",
            "description": "`apt` or `dnf` (the package from pkg.updawg.net), `binary`\n(install.sh's binaries, updated from the signed manifest), or `other`."
          }
        }
      },
      "AgentReleaseBody": {
        "type": "object",
        "description": "`GET /v1/orgs/{org}/hosts/{host_id}/events` (DAWG-105).\n\nOne release channel of the agent, as pkg.updawg.net's manifest last said.",
        "required": [
          "channel",
          "version",
          "seen_at"
        ],
        "properties": {
          "channel": {
            "type": "string",
            "description": "`stable` or `beta`."
          },
          "released_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When Updawg last read the manifest."
          },
          "version": {
            "type": "string",
            "description": "The build it holds, as agents report theirs in `agent_version`."
          }
        }
      },
      "ApiTokenBody": {
        "type": "object",
        "description": "A token as a list shows it: everything but the value.",
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "created_by",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_by": {
            "type": "string",
            "description": "The `usr_…` it acts as."
          },
          "created_by_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "id": {
            "type": "string",
            "description": "`atk_…`. The record, not the credential."
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "To the minute: written at most once a minute."
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string",
            "description": "The value's first characters, to recognise it by: `upd_AbCdEfGh`."
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Apply": {
        "type": "string",
        "description": "When an approved proposal may start.",
        "enum": [
          "asap",
          "asap_in_window"
        ]
      },
      "Approval": {
        "type": "object",
        "description": "Whether a human has to say yes, and how many of them.",
        "required": [
          "required",
          "min_approvers"
        ],
        "properties": {
          "min_approvers": {
            "type": "integer",
            "format": "int32",
            "description": "Ignored when `required` is false. Zero is meaningless and the schema\nrejects it; the engine treats anything below one as one rather than as\n\"no approvers needed\", because rounding *towards* asking is the safe\ndirection.",
            "minimum": 0
          },
          "required": {
            "type": "boolean"
          }
        }
      },
      "AuditActorBody": {
        "type": "object",
        "required": [
          "kind"
        ],
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absent for a user this organization can no longer see, such as a\nremoved member. The entry is still theirs."
          },
          "kind": {
            "type": "string",
            "description": "`user`, `system` or `policy`. ⚠️ `policy` is an auto-merge — **nobody\napproved it**, a rule did — and is not the same as `system`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AuditEntryBody": {
        "type": "object",
        "required": [
          "id",
          "at",
          "actor",
          "action",
          "metadata"
        ],
        "properties": {
          "action": {
            "type": "string",
            "description": "`host.decommissioned`, `policy.updated`, … Dotted, noun first."
          },
          "actor": {
            "$ref": "#/components/schemas/AuditActorBody"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "id": {
            "type": "string"
          },
          "ip": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where the request came from, when one did."
          },
          "metadata": {
            "type": "object",
            "description": "What the action recorded about itself. Its shape is the action's.",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "target": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AuditTargetBody"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "AuditPageBody": {
        "type": "object",
        "required": [
          "entries"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditEntryBody"
            }
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `?after=` for the next page. Absent at the end. Opaque: a\nclient passes it back and does not read it."
          }
        }
      },
      "AuditTargetBody": {
        "type": "object",
        "required": [
          "kind",
          "id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "With the kind's usual prefix (`hst_…`), or bare for a kind this build\ndoes not know."
          },
          "kind": {
            "type": "string",
            "description": "`host`, `group`, `policy`, …"
          }
        }
      },
      "Batch": {
        "type": "string",
        "description": "How often a batching rule opens a new proposal.",
        "enum": [
          "daily",
          "weekly",
          "monthly"
        ]
      },
      "BillingBody": {
        "type": "object",
        "required": [
          "plan",
          "checkout_available"
        ],
        "properties": {
          "billable_from": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "The first day usage is billed for."
          },
          "checkout_available": {
            "type": "boolean",
            "description": "Whether this deployment can take a payment: false without Stripe."
          },
          "current_period_end": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "plan": {
            "type": "string",
            "description": "`free`, `team`, `business` or `enterprise`."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stripe's subscription status, when there is a subscription:\n`active`, `trialing`, `past_due`, `canceled`, `incomplete`, …."
          }
        }
      },
      "BulkActionBody": {
        "oneOf": [
          {
            "type": "object",
            "description": "A static member of the group.",
            "required": [
              "group_id",
              "kind"
            ],
            "properties": {
              "group_id": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "add_to_group"
                ]
              }
            }
          },
          {
            "type": "object",
            "description": "Set these labels and remove those keys; every other label is kept.",
            "required": [
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "set_labels"
                ]
              },
              "remove": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "set": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                },
                "propertyNames": {
                  "type": "string"
                }
              }
            }
          },
          {
            "type": "object",
            "description": "A full inventory at the next check-in.",
            "required": [
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "refresh"
                ]
              }
            }
          },
          {
            "type": "object",
            "description": "Open a proposal to reboot them, which somebody then approves. In\n`window` if there is one, else as soon as it is approved.",
            "required": [
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "reboot"
                ]
              },
              "window": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/WindowBody"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          },
          {
            "type": "object",
            "description": "Open a proposal to update their agents to the build `channel` holds\nnow (DAWG-46), which somebody then approves. `stable` unless said.\nA host already on it, or whose agent.toml does not permit\n`self_update`, is `skipped` with the reason.",
            "required": [
              "kind"
            ],
            "properties": {
              "channel": {
                "type": "string"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "update_agent"
                ]
              }
            }
          },
          {
            "type": "object",
            "description": "Take them out of the fleet, as `DELETE …/hosts/{id}` does for one.\nOne already decommissioned is `unchanged`.",
            "required": [
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "decommission"
                ]
              }
            }
          },
          {
            "type": "object",
            "description": "Delete decommissioned hosts for good, as `…/purge` does for one. A host\nthat is not decommissioned is skipped. Cannot be undone.",
            "required": [
              "kind"
            ],
            "properties": {
              "kind": {
                "type": "string",
                "enum": [
                  "delete"
                ]
              }
            }
          }
        ],
        "description": "What to do to the hosts."
      },
      "BulkBody": {
        "type": "object",
        "required": [
          "dry_run",
          "count"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "description": "How many hosts the selection came to (a dry run), or were answered for.",
            "minimum": 0
          },
          "dry_run": {
            "type": "boolean"
          },
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkHostBody"
            },
            "description": "A dry run: the hosts it would act on."
          },
          "proposal": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BulkProposalBody",
                "description": "A reboot: the proposal it opened, to approve."
              },
              {
                "type": "null"
              }
            ]
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BulkResultBody"
            },
            "description": "Otherwise: one per host, skipped ones included."
          }
        }
      },
      "BulkFilter": {
        "type": "object",
        "properties": {
          "distro": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "label": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`key=value`, all of which a host must carry."
          },
          "reboot_required": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`yes`, `no`, `unknown`."
          },
          "status": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "BulkHostBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname"
        ],
        "properties": {
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          }
        }
      },
      "BulkProposalBody": {
        "type": "object",
        "required": [
          "id",
          "number"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "number": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "BulkRequest": {
        "type": "object",
        "description": "Which hosts a bulk action is for: by id, or every host the fleet list\nshows for a filter. Exactly one of the two.",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "$ref": "#/components/schemas/BulkActionBody"
          },
          "dry_run": {
            "type": "boolean",
            "description": "Resolve the selection and change nothing: the hosts it would act on."
          },
          "filter": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/BulkFilter",
                "description": "The fleet list's filters, as its query takes them."
              },
              {
                "type": "null"
              }
            ]
          },
          "hosts": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "`hst_…` ids."
          }
        },
        "additionalProperties": false
      },
      "BulkResultBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "outcome"
        ],
        "properties": {
          "detail": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it was skipped."
          },
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string",
            "description": "Empty for an id that is not a host here."
          },
          "outcome": {
            "type": "string",
            "description": "`changed`, `unchanged` or `skipped`."
          }
        }
      },
      "Callback": {
        "type": "object",
        "properties": {
          "code": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "GitHub sends this when the person pressed Cancel, and it is not a fault."
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "user": {
            "type": [
              "string",
              "null"
            ],
            "description": "Apple only, and only on someone's first authorization: JSON with their\nname, which its `id_token` never carries."
          }
        }
      },
      "Change": {
        "type": "object",
        "description": "What one version changed.",
        "required": [
          "version",
          "written_at",
          "added",
          "removed",
          "diff"
        ],
        "properties": {
          "added": {
            "type": "integer",
            "minimum": 0
          },
          "author": {
            "type": [
              "string",
              "null"
            ]
          },
          "diff": {
            "type": "string",
            "description": "A unified diff against the version before this one, or against nothing\nfor the first. Empty when a save changed the text not at all — which is\na real thing somebody does, and a diff of `\"\"` says so more clearly than\nan absent field."
          },
          "removed": {
            "type": "integer",
            "minimum": 0
          },
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "written_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ChangeBody": {
        "type": "object",
        "required": [
          "ecosystem",
          "package",
          "from_version",
          "to_version",
          "hosts",
          "advisories"
        ],
        "properties": {
          "advisories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdvisoryBody"
            }
          },
          "changelog": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ChangelogBody",
                "description": "What the archive's changelog says changed between the two versions\n(DAWG-71). Absent where there is none to fetch: the RHEL family, or\nan agent too old to report the source package."
              },
              {
                "type": "null"
              }
            ]
          },
          "ecosystem": {
            "type": "string"
          },
          "from_version": {
            "type": "string"
          },
          "hosts": {
            "type": "integer",
            "format": "int64",
            "description": "How many of the proposal's hosts make *this* change. Lower than the\nproposal's host count whenever the fleet is not uniform."
          },
          "package": {
            "type": "string"
          },
          "to_version": {
            "type": "string"
          }
        }
      },
      "ChangelogBody": {
        "type": "object",
        "description": "A change's changelog.",
        "required": [
          "status",
          "entries"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChangelogEntryBody"
            },
            "description": "After the installed version, up to and including the offered one,\nnewest first; at most 15."
          },
          "status": {
            "type": "string",
            "description": "`found`; `pending`, not fetched yet; or `missing`, the archive has\nnone for this version."
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ChangelogEntryBody": {
        "type": "object",
        "required": [
          "version",
          "distribution",
          "urgency",
          "changes",
          "maintainer",
          "date"
        ],
        "properties": {
          "changes": {
            "type": "string",
            "description": "The entry's lines as the maintainer wrote them."
          },
          "date": {
            "type": "string"
          },
          "distribution": {
            "type": "string",
            "description": "`trixie-security`, `jammy-updates`."
          },
          "maintainer": {
            "type": "string"
          },
          "urgency": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        }
      },
      "ChannelBody": {
        "type": "object",
        "description": "A channel as it may be shown. Never its configuration.",
        "required": [
          "id",
          "name",
          "kind",
          "display",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "display": {
            "type": "string",
            "description": "Enough to tell channels apart — `hooks.slack.com …WXYZ` — and never\nenough to use one."
          },
          "id": {
            "type": "string",
            "description": "`nch_…`."
          },
          "kind": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CheckoutBody": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "Stripe Checkout. Send the person here; they come back to the portal's\nbilling page either way."
          }
        }
      },
      "CheckoutRequest": {
        "type": "object",
        "required": [
          "plan"
        ],
        "properties": {
          "plan": {
            "type": "string",
            "description": "`team` or `business`."
          }
        },
        "additionalProperties": false
      },
      "ClassifiedUpdate": {
        "type": "object",
        "description": "One pending update, already classified against advisory data.\n\nThis is `host_updates` after `evaluate_host` has run (DAWG-56, DAWG-68):\nthe kind is decided, the advisories are attributed, and the severity is\nwhatever they said.\n\n# `Ord` is derived, and the field order is the sort order\n\nThe engine sorts the contents of a proposal so that two evaluations of the\nsame fleet produce byte-identical output. Sorting on the package name alone\nis **not** enough: two updates for the same package compare equal, the sort\nis no longer a total order, and the caller's input order leaks into the\nresult. A property test found that within a minute of being written, which\nis more than the comment asserting the opposite had managed.\n\n`package` is therefore first, and the rest of the fields follow so that any\ntwo distinguishable updates have a defined order. Reordering the fields\nchanges the sort; nothing else depends on it.",
        "required": [
          "package",
          "current_version",
          "candidate_version",
          "kind"
        ],
        "properties": {
          "advisory_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Which advisories this update would fix. Empty is not the same as\nunassessed: it means nothing published covers this package version."
          },
          "candidate_version": {
            "type": "string"
          },
          "current_version": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/UpdateKind"
          },
          "package": {
            "type": "string"
          },
          "requires_reboot": {
            "type": "boolean",
            "description": "Whether applying this one needs a reboot to take effect. From\n`domain::classify::needs_reboot`, which reads it off the package rather\nthan off the kind — a kernel security update is classified `security`,\nso the kind cannot be trusted to carry this."
          },
          "severity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Severity",
                "description": "`None` means **nobody rated it**, not \"rated as harmless\".\n\nThis is an `Option` rather than a `Severity` for the reason\n`domain::Severity` spends twenty lines on: Debian publishes a rating for\nalmost nothing, so on a Debian fleet unrated is the common case, and a\npolicy that quietly treated it as a level would be making a judgement\nnobody made. [`crate::SeverityMatch`] is where that distinction is\nenforced."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "CloudBody": {
        "type": "object",
        "description": "The cloud a host says it runs in.\n\n⚠️ **Every field is optional and the reason is the column, not the writer.**\n`hosts.cloud` is unconstrained `jsonb`. The only thing that has ever written\nit is `updawg_protocol::CloudFacts`, which has all three and requires all\nthree — but \"the only writer today\" is a claim about the present, and this\ntype is what the spec promises for ever. Absent therefore means *the host\ndid not say*, which is the same three-valued reading `reboot_required` and\n`updates` already use here, rather than a fact about the host.\n\nDeserialised rather than passed through as raw JSON, which is the whole\npoint of DAWG-261: `serde_json::Value` publishes as the empty schema, and a\ngenerated client gets `unknown` for the field or — worse, and what\n`value_type = Object` actually produced — `Record<string, never>`, an object\ntyped as never having any keys at all.\n\n⚠️ A field a newer agent sends and this server has never heard of is\n**dropped** rather than forwarded. That is the cost of the type and it is\nworth stating: nothing reads such a field today, and anything that wanted to\nwould need this struct, the spec and the portal to know about it anyway.",
        "properties": {
          "instance_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "description": "`aws`, `gcp`, `hetzner`, … as the host reported it."
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CommentBody": {
        "type": "object",
        "required": [
          "id",
          "author",
          "body",
          "written_at",
          "mentions"
        ],
        "properties": {
          "author": {
            "$ref": "#/components/schemas/PersonBody"
          },
          "body": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "mentions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PersonBody"
            },
            "description": "Who this comment addressed, as resolved when it was written.\n\nAlways present, empty when there were none, because a portal that has to\ntell `null` from `[]` will get it wrong once."
          },
          "written_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CommentRequest": {
        "type": "object",
        "properties": {
          "body": {
            "type": [
              "string",
              "null"
            ],
            "description": "`Option` so that a missing field reaches [`Body::parse`] rather than\naxum's body rejection — see the note in [`create`]. It is still\nrequired; what is optional is which of the three ways of not sending it\nthe caller chose."
          }
        }
      },
      "ComplianceGroupBody": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "ComplianceReportBody": {
        "type": "object",
        "required": [
          "generated_at",
          "since",
          "until",
          "targets",
          "summary",
          "latency",
          "latency_by_group",
          "overdue",
          "overdue_truncated"
        ],
        "properties": {
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "group": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ComplianceGroupBody",
                "description": "Absent for the whole organization."
              },
              {
                "type": "null"
              }
            ]
          },
          "latency": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LatencyBody"
            },
            "description": "Patch latency per severity, worst first."
          },
          "latency_by_group": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupLatencyBody"
            },
            "description": "The same, per group, groups by name. A host in two groups counts in\nboth."
          },
          "overdue": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OverdueBody"
            },
            "description": "Open exposures past their target, longest overdue first."
          },
          "overdue_truncated": {
            "type": "boolean",
            "description": "More are overdue than `overdue` lists; the hosts export has every\nhost's count."
          },
          "since": {
            "type": "string",
            "format": "date-time",
            "description": "The period patch latency covers."
          },
          "summary": {
            "$ref": "#/components/schemas/ComplianceSummaryBody",
            "description": "The fleet as of `generated_at`."
          },
          "targets": {
            "$ref": "#/components/schemas/PatchTargetsBody"
          },
          "until": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ComplianceSummaryBody": {
        "type": "object",
        "required": [
          "hosts",
          "active",
          "stale",
          "end_of_life",
          "past_standard_support",
          "reboot_required",
          "within_targets",
          "outside_targets",
          "overdue_exposures"
        ],
        "properties": {
          "active": {
            "type": "integer",
            "format": "int64"
          },
          "end_of_life": {
            "type": "integer",
            "format": "int64",
            "description": "Every support tier of the host's release has ended."
          },
          "hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts in scope that are not decommissioned."
          },
          "outside_targets": {
            "type": "integer",
            "format": "int64"
          },
          "overdue_exposures": {
            "type": "integer",
            "format": "int64",
            "description": "Open fixable exposures past their target, across all hosts."
          },
          "past_standard_support": {
            "type": "integer",
            "format": "int64",
            "description": "Standard support has ended, whether or not extended support has."
          },
          "reboot_required": {
            "type": "integer",
            "format": "int64"
          },
          "stale": {
            "type": "integer",
            "format": "int64"
          },
          "within_targets": {
            "type": "integer",
            "format": "int64",
            "description": "No fixable exposure older than its severity's target."
          }
        }
      },
      "Coverage": {
        "type": "object",
        "description": "An update whose coverage changes.",
        "required": [
          "package",
          "hosts"
        ],
        "properties": {
          "hosts": {
            "type": "integer",
            "description": "How many hosts it affects.",
            "minimum": 0
          },
          "package": {
            "type": "string"
          }
        }
      },
      "CreateApiTokenRequest": {
        "type": "object",
        "required": [
          "name",
          "scopes"
        ],
        "properties": {
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it stops working. Absent never expires."
          },
          "name": {
            "type": "string",
            "description": "What it is for — \"terraform\", \"CI\". Shown in the list, since the value\nnever is again."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What it may do: any of `read`, `comment`, `approve`, `rollout`,\n`jobs`, `policy`, `groups`, `hosts`, `enrollment`, `audit`,\n`integrations`, as far as your role allows."
          }
        }
      },
      "CreateChannelRequest": {
        "type": "object",
        "required": [
          "name",
          "kind",
          "config"
        ],
        "properties": {
          "config": {
            "type": "object",
            "description": "The kind's own fields: `webhook_url` for Slack and Teams; `team_id`\n(an installed workspace) and `channel` (`C…` or `#name`) for\n`slack_app`; `to` (a list\nof addresses) for email; `topic_url` and optionally `token` for ntfy;\n`routing_key` for PagerDuty; `url` for a webhook. ⚠️ Never returned.",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "kind": {
            "type": "string",
            "description": "`slack`, `slack_app`, `teams`, `email`, `ntfy`, `pagerduty` or `webhook`."
          },
          "name": {
            "type": "string",
            "description": "How rules and people pick it. Unique in the organization."
          }
        }
      },
      "CreateGroupRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "label_selector": {
            "type": [
              "object",
              "null"
            ],
            "description": "Labels a host must **all** carry, with exactly these values. Absent for\na purely static group. An empty map is refused: it would match every\nhost.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": "string"
          }
        }
      },
      "CreateRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "region": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where its data will live, `eu` or `us` (DAWG-159). Fixed once created.\nThis API's own region when not given; a region it does not serve is\nrefused.",
            "example": "eu"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional: derived from the name when it is not given."
          }
        }
      },
      "CreateRuleRequest": {
        "type": "object",
        "required": [
          "name",
          "event_types",
          "channel_ids"
        ],
        "properties": {
          "channel_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`nch_…` ids. May be empty: a rule for `proposal.auto_merged` with no\nchannels is how auto-merges are silenced."
          },
          "enabled": {
            "type": "boolean"
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`proposal.opened`, `proposal.auto_merged`, `proposal.approved`,\n`proposal.merged`, `proposal.halted`, `host.stale`, `host.recovered`,\n`release.eol`, `jobs.awaiting_signature`."
          },
          "filter": {
            "$ref": "#/components/schemas/FilterBody"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "CreateTokenRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When it stops working. Absent never expires."
          },
          "labels": {
            "type": "object",
            "description": "Put on every host that enrols with it.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "max_uses": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "How many hosts it may enrol. Absent is unlimited."
          },
          "name": {
            "type": "string",
            "description": "What it is for — \"web tier\", \"laptop test\". Shown in the list, since the\nvalue never is again."
          }
        }
      },
      "CreatedApiTokenBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiTokenBody"
          },
          {
            "type": "object",
            "required": [
              "token"
            ],
            "properties": {
              "token": {
                "type": "string",
                "description": "⚠️ **Shown once.** `upd_…`, sent as `Authorization: Bearer upd_…`."
              }
            }
          }
        ],
        "description": "The one response that carries the value."
      },
      "CreatedTokenBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TokenBody"
          },
          {
            "type": "object",
            "required": [
              "token"
            ],
            "properties": {
              "token": {
                "type": "string",
                "description": "⚠️ **Shown once.** `enr_…`. Only its hash is kept."
              }
            }
          }
        ],
        "description": "The one response that carries the value."
      },
      "Day": {
        "type": "string",
        "description": "A weekday that can live in an ordered set.\n\n`chrono::Weekday` implements `Eq` and `Hash` but not `Ord`, and every\ncollection in a policy is ordered on purpose — a `HashSet`'s iteration order\nis not an input anybody chose, and this engine's contract is that the same\ninputs give the same answer. Ordering by day-of-week from Monday is the only\nordering anybody would expect to see a window's days printed in.",
        "example": "tue"
      },
      "DecisionBody": {
        "type": "object",
        "required": [
          "decision",
          "at"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "by": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PersonBody",
                "description": "⚠️ Absent means a **policy auto-merge**, not an unknown person. A portal\nthat renders this as \"somebody\" would be attributing a machine decision\nto a human it cannot name."
              },
              {
                "type": "null"
              }
            ]
          },
          "decision": {
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "DecommissionedBody": {
        "type": "object",
        "required": [
          "decommissioned_at",
          "already",
          "proposals_left",
          "proposals_closed"
        ],
        "properties": {
          "already": {
            "type": "boolean",
            "description": "It already was; nothing changed."
          },
          "decommissioned_at": {
            "type": "string",
            "format": "date-time"
          },
          "proposals_closed": {
            "type": "integer",
            "description": "Of those, the ones it left empty — now closed as `obsolete`.",
            "minimum": 0
          },
          "proposals_left": {
            "type": "integer",
            "description": "Proposals nobody had approved that the host was taken out of.",
            "minimum": 0
          }
        }
      },
      "DeleteRequest": {
        "type": "object",
        "required": [
          "confirm"
        ],
        "properties": {
          "confirm": {
            "type": "string",
            "description": "The organization's slug, exactly as it is now: a thing typed on purpose\nrather than a click somebody could make by accident."
          }
        }
      },
      "DeletedBody": {
        "type": "object",
        "required": [
          "hostname"
        ],
        "properties": {
          "hostname": {
            "type": "string",
            "description": "What it was called, for the confirmation."
          }
        }
      },
      "DeletedGroupBody": {
        "type": "object",
        "required": [
          "proposals_unlinked",
          "tokens_unlinked",
          "policies_naming_it"
        ],
        "properties": {
          "policies_naming_it": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Live policies whose selector names it. Not changed — they are the\noperator's text — and now match nothing of it."
          },
          "proposals_unlinked": {
            "type": "integer",
            "format": "int64",
            "description": "Proposals that pointed at the group, now pointing at none."
          },
          "tokens_unlinked": {
            "type": "integer",
            "format": "int64",
            "description": "Enrollment tokens whose default group it was, now with none."
          }
        }
      },
      "DeliveryBody": {
        "type": "object",
        "description": "One delivery, as the channel's log shows it.",
        "required": [
          "id",
          "event_type",
          "status",
          "attempts",
          "created_at"
        ],
        "properties": {
          "attempts": {
            "type": "integer",
            "format": "int32"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "event_type": {
            "type": "string",
            "description": "`proposal.halted`, `host.stale`, …, or `test`."
          },
          "id": {
            "type": "string"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ],
            "description": "The other side's words, or ours. Never the destination."
          },
          "status": {
            "type": "string",
            "description": "`pending` (being tried), `delivered`, or `failed` — every attempt\nused, the dead letter. A failed one can be replayed."
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Detail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Summary"
          },
          {
            "type": "object",
            "required": [
              "showing",
              "yaml",
              "written_at"
            ],
            "properties": {
              "author": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "showing": {
                "type": "integer",
                "format": "int32",
                "description": "The version this body carries, which differs from `version` when an\nolder one was asked for. Both are here on purpose: a portal showing\nversion 2 of a policy on version 5 needs to know it is looking at\nhistory rather than at the policy."
              },
              "written_at": {
                "type": "string",
                "format": "date-time"
              },
              "yaml": {
                "type": "string",
                "description": "Byte for byte what somebody wrote. The compiled form is derived from it\nand is not handed back — there is one source of truth for what a policy\nsays and it is the text."
              }
            }
          }
        ]
      },
      "DigestBody": {
        "type": "object",
        "required": [
          "frequency"
        ],
        "properties": {
          "frequency": {
            "type": "string",
            "description": "`off`, `daily` or `weekly`. Sent at 08:00 in your time zone; weekly on\nMondays."
          },
          "mention_email": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether you are emailed when somebody mentions you in a comment here\n(DAWG-247). On unless turned off. Absent on a `PUT` leaves it alone."
          }
        }
      },
      "EndorseRequest": {
        "type": "object",
        "properties": {
          "endorsement": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/EndorsementBody",
                "description": "Your active key endorsing the next one, from `updawgctl endorse`.\nRequired; optional here only so a missing one is answered after the\npermission check."
              },
              {
                "type": "null"
              }
            ]
          },
          "proof": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/KeyProof",
                "description": "The next key proving its holder can sign with it, from `updawgctl\nprove-key`. Required, for the reason a hand-over requires one."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "EndorsedBody": {
        "type": "object",
        "required": [
          "key",
          "from"
        ],
        "properties": {
          "from": {
            "type": "string",
            "description": "The key it replaced, now retiring."
          },
          "key": {
            "type": "string",
            "description": "The new active key."
          }
        }
      },
      "EndorsementBody": {
        "type": "object",
        "description": "An endorsement: the statement's canonical JSON and the signature over it,\nas `updawgctl endorse` prints them.",
        "required": [
          "statement",
          "signature"
        ],
        "properties": {
          "signature": {
            "type": "string",
            "description": "Base64 Ed25519 signature over `updawg-endorsement-v1\\0` and `statement`."
          },
          "statement": {
            "type": "string",
            "description": "The statement's canonical JSON, exactly as signed."
          }
        }
      },
      "EraseRequest": {
        "type": "object",
        "description": "What `DELETE /v1/me` needs: the caller's own address, typed back.",
        "required": [
          "confirm"
        ],
        "properties": {
          "confirm": {
            "type": "string",
            "description": "The email address of the account being erased, exactly as it is. The\none thing a stray click, a stolen CSRF token or a confused client cannot\nsupply by accident."
          }
        }
      },
      "ExportBody": {
        "type": "object",
        "required": [
          "id",
          "kind",
          "status",
          "since",
          "until",
          "created_at",
          "expires_at"
        ],
        "properties": {
          "bytes": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "download": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where to `GET` the file, while it can be: the API path, relative to\nthe API's own address."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it failed."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "After this the file is no longer handed out."
          },
          "filename": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the download is called, once ready."
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "group": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ComplianceGroupBody",
                "description": "The group as it was named when the export was asked for. Absent for\nthe whole organization."
              },
              {
                "type": "null"
              }
            ]
          },
          "id": {
            "type": "string",
            "description": "`exp_…`."
          },
          "kind": {
            "$ref": "#/components/schemas/ExportKindBody"
          },
          "requested_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "`usr_…`; absent once that person's account is gone."
          },
          "rows": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Data rows, for a CSV."
          },
          "since": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/ExportStatusBody"
          },
          "until": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ExportKindBody": {
        "type": "string",
        "description": "What an export contains.",
        "enum": [
          "hosts_csv",
          "resolutions_csv",
          "report_pdf"
        ]
      },
      "ExportListBody": {
        "type": "object",
        "required": [
          "exports"
        ],
        "properties": {
          "exports": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExportBody"
            },
            "description": "The most recent, newest first."
          }
        }
      },
      "ExportRequest": {
        "type": "object",
        "properties": {
          "group": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only the hosts this group (`grp_…`) resolves to when the export is made."
          },
          "kind": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ExportKindBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "since": {
            "type": [
              "string",
              "null"
            ],
            "description": "Start of the patch-latency period (RFC 3339), for `resolutions_csv` and\n`report_pdf`. Default: 90 days before `until`."
          },
          "until": {
            "type": [
              "string",
              "null"
            ],
            "description": "End of the period, exclusive. Default: now."
          }
        }
      },
      "ExportStatusBody": {
        "type": "string",
        "description": "Where an export is.",
        "enum": [
          "queued",
          "running",
          "ready",
          "failed"
        ]
      },
      "ExposedHostBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "package",
          "installed",
          "fixed_version",
          "fixable",
          "first_seen_at"
        ],
        "properties": {
          "first_seen_at": {
            "type": "string",
            "format": "date-time"
          },
          "fixable": {
            "type": "boolean",
            "description": "Whether an update available to the host reaches `fixed_version`."
          },
          "fixed_version": {
            "type": "string",
            "description": "The version the advisory says fixes it."
          },
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "installed": {
            "type": "string"
          },
          "package": {
            "type": "string"
          }
        }
      },
      "ExposureAdvisoryBody": {
        "type": "object",
        "required": [
          "id",
          "source",
          "external_id",
          "title",
          "cves"
        ],
        "properties": {
          "cves": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "external_id": {
            "type": "string",
            "description": "`USN-7012-1`, `DSA-6335-1`, `RLSA-2026:67165`, …"
          },
          "id": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ExposureBody": {
        "type": "object",
        "required": [
          "package",
          "installed",
          "fixed_version",
          "fixable",
          "first_seen_at",
          "advisory"
        ],
        "properties": {
          "advisory": {
            "$ref": "#/components/schemas/ExposureAdvisoryBody"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When this installed version was first seen exposed."
          },
          "fixable": {
            "type": "boolean",
            "description": "Whether an update available to this host reaches `fixed_version`.\n`false` is the urgent case: affected, and nothing to install."
          },
          "fixed_version": {
            "type": "string",
            "description": "The version the advisory says fixes it."
          },
          "installed": {
            "type": "string"
          },
          "package": {
            "type": "string"
          },
          "severity": {
            "type": [
              "string",
              "null"
            ],
            "description": "Normalised, from the vendor's rating or else the worst CVSS. `null`\nmeans nobody rated it, which is not the same as harmless."
          }
        }
      },
      "ExposureListBody": {
        "type": "object",
        "required": [
          "unfixable",
          "exposures"
        ],
        "properties": {
          "exposures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExposureBody"
            }
          },
          "unfixable": {
            "type": "integer",
            "description": "How many of `exposures` no available update fixes.",
            "minimum": 0
          }
        }
      },
      "FilterBody": {
        "type": "object",
        "description": "What a rule narrows its events by. Every field optional; all given must\nhold. The proposal fields do not narrow host events.",
        "properties": {
          "known_exploited": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Only proposals that fix something known to be exploited (`true`), or\nonly those that do not (`false`)."
          },
          "min_severity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Severity",
                "description": "At least this severe."
              },
              {
                "type": "null"
              }
            ]
          },
          "proposal_kinds": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Only these kinds of proposal: `security`, `bugfix`, …"
          }
        },
        "additionalProperties": false
      },
      "FleetAdvisoryBody": {
        "type": "object",
        "required": [
          "id",
          "source",
          "external_id",
          "title",
          "cves",
          "known_exploited",
          "hosts",
          "fixable_hosts",
          "first_seen_at"
        ],
        "properties": {
          "cves": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "external_id": {
            "type": "string",
            "description": "`USN-7012-1`, `DSA-6335-1`, `RLSA-2026:67165`, …"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the earliest of those exposures was first seen."
          },
          "fixable_hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Of those, the ones an available update fixes."
          },
          "hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts with an installed version it affects."
          },
          "id": {
            "type": "string"
          },
          "known_exploited": {
            "type": "boolean",
            "description": "A CVE it lists is in CISA's Known Exploited Vulnerabilities."
          },
          "severity": {
            "type": [
              "string",
              "null"
            ],
            "description": "Normalised, from the vendor's rating or else the worst CVSS. `null`\nmeans nobody rated it, which is not the same as harmless."
          },
          "source": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "FleetHost": {
        "type": "object",
        "description": "One host and the updates it has outstanding.",
        "required": [
          "host",
          "updates"
        ],
        "properties": {
          "host": {
            "$ref": "#/components/schemas/HostState"
          },
          "updates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClassifiedUpdate"
            }
          }
        }
      },
      "FrozenBody": {
        "type": "object",
        "description": "What pins a host's package sources in time, as its agent reported it\n(DAWG-233).",
        "required": [
          "kind",
          "pinned",
          "behind"
        ],
        "properties": {
          "behind": {
            "type": "boolean",
            "description": "Known to be behind what it is offered. `false` also when nobody can\ntell."
          },
          "kind": {
            "type": "string",
            "description": "`releasever` (dnf's release is fixed: Amazon Linux 2023, or\n`/etc/dnf/vars/releasever`), `snapshot` (apt sources on a dated\narchive snapshot), or `other` from an agent newer than this server."
          },
          "latest": {
            "type": [
              "string",
              "null"
            ],
            "description": "The newest release it is offered, where its agent can tell."
          },
          "pinned": {
            "type": "string",
            "description": "What it is pinned to: `2023.5.20240805`, `9.2`, `20240101T000000Z`."
          }
        }
      },
      "GroupBody": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "GroupDetailBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/HostGroupBody"
          },
          {
            "type": "object",
            "required": [
              "hosts"
            ],
            "properties": {
              "hosts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/GroupHostBody"
                }
              }
            }
          }
        ]
      },
      "GroupHostBody": {
        "type": "object",
        "required": [
          "id",
          "hostname",
          "static",
          "by_label"
        ],
        "properties": {
          "by_label": {
            "type": "boolean",
            "description": "Matched by the label selector. Both may be true."
          },
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "static": {
            "type": "boolean",
            "description": "Put in the group by hand."
          }
        }
      },
      "GroupLatencyBody": {
        "type": "object",
        "required": [
          "group",
          "latency"
        ],
        "properties": {
          "group": {
            "$ref": "#/components/schemas/ComplianceGroupBody"
          },
          "latency": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LatencyBody"
            }
          }
        }
      },
      "GroupedBody": {
        "type": "object",
        "required": [
          "by",
          "overlapping",
          "sections"
        ],
        "properties": {
          "by": {
            "type": "string",
            "description": "`policy` or `group`, as asked."
          },
          "overlapping": {
            "type": "boolean",
            "description": "⚠️ `true` when a proposal can be in more than one section, so the totals\nadd up to more than the inbox holds: by group, a proposal across hosts in\ntwo groups is in both."
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SectionBody"
            }
          }
        }
      },
      "HaltOn": {
        "type": "object",
        "properties": {
          "failed_health_checks": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "failed_jobs": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          }
        }
      },
      "HaltOnBody": {
        "type": "object",
        "required": [
          "failed_jobs",
          "failed_health_checks"
        ],
        "properties": {
          "failed_health_checks": {
            "type": "integer",
            "format": "int32",
            "description": "Failed health checks that halt the rollout. Zero means none do.",
            "minimum": 0
          },
          "failed_jobs": {
            "type": "integer",
            "format": "int32",
            "description": "Failed jobs that halt the rollout. Zero means none do.",
            "minimum": 0
          }
        }
      },
      "HandOverRequest": {
        "type": "object",
        "properties": {
          "proof": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/KeyProof",
                "description": "What `updawgctl prove-key` printed. Required; optional here only so a\nmissing one is answered after the permission check."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "HealthCheckBody": {
        "type": "object",
        "required": [
          "name",
          "passed",
          "duration_ms"
        ],
        "properties": {
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "duration_ms": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "name": {
            "type": "string"
          },
          "passed": {
            "type": "boolean"
          }
        }
      },
      "HistoryBody": {
        "type": "object",
        "required": [
          "total",
          "versions"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "format": "int64",
            "description": "Every version there has ever been, however many are in `versions`."
          },
          "versions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Change"
            }
          }
        }
      },
      "HostBody": {
        "type": "object",
        "required": [
          "id",
          "machine_id",
          "hostname",
          "status",
          "labels",
          "os_family",
          "distro",
          "distro_version",
          "arch",
          "agent_mode",
          "agent_permissions",
          "services_need_restart",
          "enrolled_at"
        ],
        "properties": {
          "agent_install": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/AgentInstallBody",
                "description": "How its agent was installed and the channel it follows. A package\ninstall updates only to builds its own repository's channel holds.\nAbsent: an agent too old to say."
              },
              {
                "type": "null"
              }
            ]
          },
          "agent_mode": {
            "type": "string",
            "description": "⚠️ A **ceiling**, not a setting. The host's own `agent.toml` decides\nthis; the server may narrow it and can never widen it. A portal that\nrenders it as editable is describing a control that does not exist."
          },
          "agent_permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "agent_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "arch": {
            "type": "string"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "distro": {
            "type": "string"
          },
          "distro_version": {
            "type": "string"
          },
          "enrolled_at": {
            "type": "string",
            "format": "date-time"
          },
          "frozen": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FrozenBody",
                "description": "Its package sources are pinned in time (DAWG-233): `updates` is\nmeasured against a snapshot that does not move. ⚠️ Zero updates on a\nfrozen host is **not** \"patched\", least of all when `behind`."
              },
              {
                "type": "null"
              }
            ]
          },
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "kernel_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "type": "object",
            "description": "⚠️ A **selector**, not decoration. A policy that targets several labels\nintersects them, and the fleet filter takes them as repeatable\n`key=value`, so a client that cannot see the type cannot build either.\nString to string, enforced by `hosts_labels_are_strings` rather than\nasserted here (DAWG-261).",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "last_inventory_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_seen_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "machine_id": {
            "type": "string",
            "description": "Identity, and not the hostname. Hostnames change and repeat."
          },
          "os_family": {
            "type": "string"
          },
          "pinned_keys": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "The organization signing keys (`sk_…`) its agent verifies jobs\nagainst, as it said at its last check-in. Before retiring a key, every\nhost should list its successor here. Absent: an agent too old to say,\nwhich is not a host that pins nothing."
          },
          "reboot_required": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "⚠️ Three-valued. `null` is \"this host cannot say\", which is **not**\n`false`. A distribution with no way to answer must not read as \"nothing\nto do here\"."
          },
          "services_need_restart": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "snapshots": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SnapshotsBody",
                "description": "Whether this host can take snapshots, and so be rolled back\n(DAWG-115). ⚠️ `null` is an agent too old to say, **not** a host that\ncannot: that one has a `reason` and no `provider`."
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string"
          },
          "updates": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/UpdatesBody",
                "description": "⚠️ `null` means **never evaluated**, not zero. A host that has never\nuploaded an inventory has never been looked at, and rendering that as\n\"0 updates\" tells somebody their unevaluated fleet is fully patched."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "HostDetailBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/HostBody"
          },
          {
            "type": "object",
            "required": [
              "groups",
              "proposals",
              "held_packages",
              "advisory_coverage"
            ],
            "properties": {
              "advisory_coverage": {
                "type": "string",
                "description": "Whether anything rates this host's updates (DAWG-215):\n\n- `covered`: advisories are published for its release.\n- `no_feed`: its release is known and no advisory feed covers it — a\n  derivative like Linux Mint, Pop!_OS or Raspbian. ⚠️ Every update\n  here is unrated, which is not the same as safe.\n- `unknown_release`: not resolved to a known release yet."
              },
              "cert_expires_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "cloud": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CloudBody",
                    "description": "What the host said about the cloud it runs in, or absent because it is\nnot in one."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "decommissioned_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "groups": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/GroupBody"
                }
              },
              "held_packages": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "⚠️ An update for a held package will not install. This is the answer to\n\"why did nothing happen\" before anybody has to ask it."
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Free text for whoever looks after the box."
              },
              "proposals": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ProposalBody"
                },
                "description": "Open proposals only, newest first. A host that has been in four hundred\nmerged proposals is the normal case, and listing them would make this a\nchangelog rather than an answer to \"is anything waiting on this box\"."
              },
              "virtualization": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        ]
      },
      "HostEventBody": {
        "type": "object",
        "required": [
          "id",
          "at",
          "kind",
          "data"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "description": "What the event recorded. A job's events carry `job` (`job_…`); a\nfinished one also `status`, `changes` and `error`.",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "`job_finished`, `rejected_by_host`, `job_expired`, `went_stale`,\n`recovered` — or something newer, passed through as stored."
          }
        }
      },
      "HostEventPageBody": {
        "type": "object",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostEventBody"
            }
          },
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `?after=` for the next page. Absent at the end. Opaque."
          }
        }
      },
      "HostGroupBody": {
        "type": "object",
        "required": [
          "id",
          "name",
          "static_hosts",
          "resolved_hosts",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "type": "string",
            "description": "`grp_…`."
          },
          "label_selector": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": "string"
          },
          "resolved_hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Every host it resolves to, static or by label, each counted once.\nDecommissioned hosts are in no group."
          },
          "static_hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts put in the group by hand. Decommissioned hosts are not counted."
          }
        }
      },
      "HostId": {
        "type": "string",
        "format": "uuid",
        "description": "An enrolled host."
      },
      "HostListBody": {
        "type": "object",
        "required": [
          "total",
          "hosts"
        ],
        "properties": {
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HostBody"
            }
          },
          "next": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "HostState": {
        "type": "object",
        "description": "A host as the engine sees it.",
        "required": [
          "id"
        ],
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The groups this host belongs to, by name."
          },
          "id": {
            "$ref": "#/components/schemas/HostId"
          },
          "labels": {
            "type": "object",
            "description": "The host's labels. A map rather than pairs, because a host cannot have\none label twice and the type should say so.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "reboot_required": {
            "type": "boolean",
            "description": "Whether the host is *already* waiting for a reboot, before any of these\nupdates are applied. Not a selector today; carried because a proposal\nthat will add a second reboot requirement to a host already needing one\nis worth showing, and because leaving it out of the input would make\nadding it later a change to every caller."
          }
        }
      },
      "HostsSetBody": {
        "type": "object",
        "required": [
          "static_hosts"
        ],
        "properties": {
          "static_hosts": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "InvitationBody": {
        "type": "object",
        "required": [
          "id",
          "email",
          "role",
          "expires_at"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "id": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          }
        }
      },
      "InviteRequest": {
        "type": "object",
        "required": [
          "email",
          "role"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          }
        }
      },
      "JobBody": {
        "type": "object",
        "required": [
          "id",
          "host",
          "kind",
          "status",
          "created_at",
          "expires_at",
          "pinned",
          "changes",
          "health_checks",
          "report_unreadable"
        ],
        "properties": {
          "changes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackageChangeBody"
            },
            "description": "What the host reported changed. Empty until it reports."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "The host's error, when it ran the job and it failed."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "health_checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HealthCheckBody"
            }
          },
          "host": {
            "$ref": "#/components/schemas/JobHostBody"
          },
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "description": "`apply_updates`, `reboot`, … or `unknown` for a document this build\ncannot read."
          },
          "pinned": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PackageChangeBody"
            },
            "description": "The exact versions the job was signed to install. Empty for a kind\nthat installs nothing named."
          },
          "reboot_required": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "`null` until the host reports."
          },
          "rejection_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why the host refused it, when it did. A refusal is normal: the host's\nown configuration always wins."
          },
          "report_unreadable": {
            "type": "boolean",
            "description": "There is a report and this build cannot read it. Never true alongside\nany of the fields above."
          },
          "retried_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Set when a person resumed past this job's failure, and its host was\nsent a new job, which is listed too (DAWG-110)."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "description": "`awaiting_signature` (a customer-held key's job, waiting for\n`updawgctl sign`), `queued`, `delivered`, `running`, `succeeded`,\n`failed`, `rejected_by_host`, `cancelled` or `expired`. Anything else\nis passed through as stored."
          }
        }
      },
      "JobHostBody": {
        "type": "object",
        "required": [
          "id",
          "hostname"
        ],
        "properties": {
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "JobListBody": {
        "type": "object",
        "required": [
          "jobs"
        ],
        "properties": {
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobBody"
            }
          }
        }
      },
      "JoinRequest": {
        "type": "object",
        "required": [
          "token",
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The person's name, as their colleagues will see it."
          },
          "token": {
            "type": "string"
          }
        }
      },
      "JoinedBody": {
        "type": "object",
        "required": [
          "org",
          "role"
        ],
        "properties": {
          "org": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          }
        }
      },
      "JsonValue": {
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "number"
          },
          {
            "type": "boolean"
          },
          {
            "type": "null"
          },
          {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JsonValue"
            }
          },
          {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            }
          }
        ]
      },
      "KeyProof": {
        "type": "object",
        "description": "The organization's key endorsing **itself**, for this organization.\n\nAn endorsement statement (`updawg-endorsement-v1`) whose `previous_key` and\n`new_key` are both the key being handed over to, and whose `org_id` is this\norganization's. It proves the key's holder can sign with it — a hand-over\nto a key nobody holds leaves the organization unable to sign anything, and\nnothing Updawg holds can undo it — and it cannot be put to use as an\nendorsement: an agent accepts one only from a key it already trusts, and a\nkey vouching for itself vouches for nothing new.",
        "required": [
          "statement",
          "signature"
        ],
        "properties": {
          "signature": {
            "type": "string",
            "description": "Base64 Ed25519 signature over `updawg-endorsement-v1\\0` and `statement`."
          },
          "statement": {
            "type": "string",
            "description": "The statement's canonical JSON, exactly as signed."
          }
        }
      },
      "LatencyBody": {
        "type": "object",
        "required": [
          "resolved",
          "median_hours",
          "p90_hours",
          "mean_hours"
        ],
        "properties": {
          "mean_hours": {
            "type": "number",
            "format": "double"
          },
          "median_hours": {
            "type": "number",
            "format": "double",
            "description": "Hours from a fix being available to it being installed."
          },
          "p90_hours": {
            "type": "number",
            "format": "double"
          },
          "resolved": {
            "type": "integer",
            "format": "int64",
            "description": "Exposures to this severity that ended in the period."
          },
          "severity": {
            "type": [
              "string",
              "null"
            ],
            "description": "`critical`, `high`, `medium`, `low` or `none`; absent for advisories\nnobody rated."
          },
          "target_days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "The organization's target for this severity; absent for `none` and\nunrated."
          },
          "within_target": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "How many of `resolved` were within the target."
          }
        }
      },
      "LivePolicy": {
        "type": "object",
        "description": "A live policy, as the identity checks need it.",
        "required": [
          "id",
          "name",
          "version"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/PolicyId"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "Which version is in force."
          }
        }
      },
      "LogBody": {
        "type": "object",
        "required": [
          "lines",
          "more",
          "finished"
        ],
        "properties": {
          "finished": {
            "type": "boolean",
            "description": "The job has finished. With `more` false, nothing further will arrive —\nbar a last batch that is still in flight, for a few seconds."
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LogLineBody"
            }
          },
          "more": {
            "type": "boolean",
            "description": "Ask again with `after` = the last line's `seq` for what follows."
          }
        }
      },
      "LogLineBody": {
        "type": "object",
        "required": [
          "seq",
          "at",
          "stream",
          "line"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "line": {
            "type": "string"
          },
          "seq": {
            "type": "integer",
            "format": "int64",
            "minimum": 0
          },
          "stream": {
            "type": "string",
            "description": "`agent`, `stdout` or `stderr`."
          }
        }
      },
      "MagicLinkRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string"
          }
        }
      },
      "MaintenanceWindow": {
        "type": "object",
        "description": "When a policy is willing to let work happen.",
        "required": [
          "start",
          "duration",
          "timezone"
        ],
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Day"
            },
            "description": "Empty means every day. The design document's example lists three.",
            "uniqueItems": true
          },
          "duration": {
            "type": "string"
          },
          "start": {
            "type": "string",
            "description": "Local wall-clock time in `timezone`, not UTC. A window written `02:00`\nis meant to stay at two in the morning through a clock change, which is\nthe entire reason this field is not an offset."
          },
          "timezone": {
            "type": "string",
            "example": "Europe/London"
          }
        }
      },
      "Manager": {
        "type": "string",
        "description": "A tool that owns a policy's text.",
        "enum": [
          "terraform"
        ]
      },
      "Match": {
        "type": "object",
        "description": "What an update has to look like for a rule to catch it.\n\nEvery field is a filter, and they are `AND`ed. A `Match` with nothing set\ncatches every update, which is how the example policy's last-resort rules\nare written.",
        "properties": {
          "kind": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/UpdateKind"
            },
            "description": "`None` means any kind.",
            "uniqueItems": true
          },
          "packages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Pattern"
            },
            "description": "Empty means any package.",
            "uniqueItems": true
          },
          "severity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SeverityMatch",
                "description": "`None` means any severity, **including unrated**."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "Me": {
        "type": "object",
        "required": [
          "id",
          "email",
          "timezone",
          "memberships",
          "csrf_token"
        ],
        "properties": {
          "csrf_token": {
            "type": "string",
            "description": "The token every mutation has to echo in `X-Updawg-Csrf`.\n\nReturned here as well as at sign-in, so a page that has been reloaded\ncan get one without signing in again. It is safe to put in this body and\nnot in a cookie: a cross-origin page cannot read a response, and a\ncookie would travel on every request whether it was wanted or not."
          },
          "email": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "memberships": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Membership"
            },
            "description": "Organizations this person belongs to, and what they may do in each."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": "string"
          }
        }
      },
      "MemberBody": {
        "type": "object",
        "required": [
          "user_id",
          "email",
          "role",
          "joined_at"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "joined_at": {
            "type": "string",
            "format": "date-time"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          },
          "user_id": {
            "type": "string"
          }
        }
      },
      "Membership": {
        "type": "object",
        "required": [
          "org",
          "slug",
          "name",
          "plan",
          "role",
          "region"
        ],
        "properties": {
          "api_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "The API base to send this organization's requests to: its region's.\n`null` when this deployment does not know that region's address."
          },
          "name": {
            "type": "string"
          },
          "org": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "description": "Where the organization's data lives, `eu` or `us` (DAWG-159)."
          },
          "role": {
            "$ref": "#/components/schemas/Role"
          },
          "slug": {
            "type": "string"
          }
        }
      },
      "OrgBody": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "name",
          "plan",
          "region",
          "role",
          "stale_after_minutes",
          "eol_lead_days",
          "audit_retention_max_days",
          "agent_auto_update"
        ],
        "properties": {
          "agent_auto_update": {
            "type": "boolean",
            "description": "Whether agents are kept on the stable channel automatically (DAWG-46)."
          },
          "audit_retention_days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Days the audit log is kept if fewer than the plan keeps, or `null` for\nthe plan's whole window (DAWG-160)."
          },
          "audit_retention_max_days": {
            "type": "integer",
            "format": "int32",
            "description": "The most `audit_retention_days` may be on this plan."
          },
          "changes_paused_from": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When changes stop for it, a week after `over_allowance_since`: from\nthen hosts keep reporting but nothing is installed or rebooted, and\napproving is refused, until it is back within Free or on a paid plan."
          },
          "eol_lead_days": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Days before a release's support ends to raise `release.eol`, longest\nfirst (DAWG-70). 180, 90 and 30 unless somebody changed them."
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "over_allowance_since": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When this Free organization was first seen over the Free allowance —\nmore hosts than Free allows, or its owner's second Free organization —\nor `null` when it is within it or on a paid plan (DAWG-295). Checked\nnightly."
          },
          "plan": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "description": "Where its data lives, `eu` or `us` (DAWG-159). Fixed at creation."
          },
          "role": {
            "$ref": "#/components/schemas/Role",
            "description": "The caller's role, on every representation of an organization.\n\nThe portal needs it to decide what to render, and fetching it from\n`GET /me` instead would mean the two can disagree after somebody's role\nchanges in another tab."
          },
          "slug": {
            "type": "string"
          },
          "stale_after_minutes": {
            "type": "integer",
            "format": "int32",
            "description": "Minutes without a check-in before a host is marked stale (DAWG-62).\n5 to 10,080; 30 unless somebody changed it."
          }
        }
      },
      "OriginBody": {
        "type": "object",
        "required": [
          "id",
          "version"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absent if the policy has since been hard-deleted."
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "The version this proposal was generated under, which is very possibly\nnot the current one. That is the point of storing it."
          }
        }
      },
      "OverdueBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "package",
          "advisory",
          "severity",
          "fixable_since",
          "target_days",
          "due_at"
        ],
        "properties": {
          "advisory": {
            "type": "string",
            "description": "`USN-7012-1`, `DSA-5800-1`, …"
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it fell due: `fixable_since` plus `target_days`."
          },
          "fixable_since": {
            "type": "string",
            "format": "date-time",
            "description": "When an update reaching the fix became available."
          },
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "package": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "target_days": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "PackageChangeBody": {
        "type": "object",
        "required": [
          "name",
          "arch",
          "from",
          "to"
        ],
        "properties": {
          "arch": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "to": {
            "type": "string"
          }
        }
      },
      "PatchTargetsBody": {
        "type": "object",
        "required": [
          "critical",
          "high",
          "medium",
          "low"
        ],
        "properties": {
          "critical": {
            "type": "integer",
            "format": "int32",
            "description": "Days to patch a fixable critical exposure. 1 to 365."
          },
          "high": {
            "type": "integer",
            "format": "int32"
          },
          "low": {
            "type": "integer",
            "format": "int32"
          },
          "medium": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "Pattern": {
        "type": "string",
        "description": "A package-name glob: `*` and `?`, not a regular expression.",
        "example": "openssl*"
      },
      "PersonBody": {
        "type": "object",
        "required": [
          "id",
          "email"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "PlanBody": {
        "type": "object",
        "description": "An unfinished release upgrade, and where its hosts stand.",
        "required": [
          "proposal_id",
          "number",
          "status",
          "to_version",
          "hosts",
          "preflight",
          "stuck"
        ],
        "properties": {
          "group": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PlanGroupBody",
                "description": "The group it was planned for. Absent for every host on the release."
              },
              {
                "type": "null"
              }
            ]
          },
          "hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts it targets that are still in the fleet."
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "preflight": {
            "$ref": "#/components/schemas/StandingBody",
            "description": "How many hosts stand where after their current preflight."
          },
          "proposal_id": {
            "type": "string",
            "description": "The `prp_…` id of its proposal."
          },
          "status": {
            "type": "string"
          },
          "stuck": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StuckBody"
            },
            "description": "Each host a check failed on, or that finished without answering, and\nwhy."
          },
          "to_version": {
            "type": "string",
            "description": "The target, by version."
          }
        }
      },
      "PlanGroupBody": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "PlanUpgradeRequest": {
        "type": "object",
        "required": [
          "distro",
          "from",
          "to"
        ],
        "properties": {
          "distro": {
            "type": "string",
            "description": "As `distro` on a host: `debian`."
          },
          "from": {
            "type": "string",
            "description": "The release its hosts run now: `13`."
          },
          "group_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Only the hosts in this group (`grp_…`). Absent is every host on `from`."
          },
          "to": {
            "type": "string",
            "description": "The release to move them to: `14`. One of `from`'s `targets`."
          }
        }
      },
      "PlannedBody": {
        "type": "object",
        "required": [
          "proposal_id",
          "number",
          "hosts"
        ],
        "properties": {
          "hosts": {
            "type": "integer",
            "format": "int64",
            "description": "The hosts it targets."
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "proposal_id": {
            "type": "string",
            "description": "The `prp_…` id of the `dist_upgrade` proposal."
          }
        }
      },
      "Policy": {
        "type": "object",
        "description": "One policy, as the engine sees it.",
        "required": [
          "id",
          "version",
          "name",
          "priority",
          "enabled",
          "selector",
          "rules"
        ],
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "$ref": "#/components/schemas/PolicyId"
          },
          "maintenance_window": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MaintenanceWindow"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "priority": {
            "type": "integer",
            "format": "int32",
            "description": "Higher wins. The column defaults to 100, which is what the design\ndocument's example uses."
          },
          "rollouts": {
            "type": "object",
            "description": "Named rollout strategies a rule may refer to. The engine only carries\nthe name through to the intent — staged rollouts are epic 09, and what\na stage *does* is not a decision this function makes.",
            "additionalProperties": {
              "$ref": "#/components/schemas/Rollout"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Rule"
            },
            "description": "Evaluated in order. The first rule that matches an update decides it."
          },
          "selector": {
            "$ref": "#/components/schemas/Selector"
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "The row in `policy_versions` this came from. It travels into every\nproposal so \"why was this proposed\" stays answerable after an edit."
          }
        }
      },
      "PolicyId": {
        "type": "string",
        "format": "uuid",
        "description": "A policy."
      },
      "PolicyProblem": {
        "type": "object",
        "description": "One thing wrong with a policy, where an editor can put a marker.",
        "required": [
          "detail"
        ],
        "properties": {
          "column": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "detail": {
            "type": "string",
            "description": "The path serde walked, then what went wrong: `rules[0]: unknown field\n...`. The location is **not** repeated here — it is `line` and `column`."
          },
          "line": {
            "type": [
              "integer",
              "null"
            ],
            "description": "One-based, as an editor counts. Absent for the two checks that need the\nwhole document and so have no line of their own: a rule naming a\nrollout the policy does not define, and `apply: asap_in_window` with no\nwindow. Both name the rule by index in `detail` instead.",
            "minimum": 0
          }
        }
      },
      "PolicyRequest": {
        "type": "object",
        "properties": {
          "yaml": {
            "type": [
              "string",
              "null"
            ],
            "description": "`Option` so that a missing field produces this API's own 400 rather\nthan axum's plain-text 422 — see DAWG-246 and the note in\n`routes::proposals::reject`."
          }
        }
      },
      "PreflightBody": {
        "type": "object",
        "description": "A proposal's preflight.",
        "required": [
          "hosts"
        ],
        "properties": {
          "blocked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why one cannot be asked for now. Absent when it can."
          },
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PreflightHostBody"
            },
            "description": "Every host the proposal targets that is still in the fleet."
          },
          "requested": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RollbackRequestedBody",
                "description": "Who asked last, and when. Absent until somebody does."
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "PreflightCheckBody": {
        "type": "object",
        "required": [
          "name",
          "status",
          "summary",
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The specifics: a package, a file, a module."
          },
          "name": {
            "type": "string",
            "description": "Stable, for code: `disk_space`, `held_packages`, `modified_conffiles`,\n`dkms_modules`, `snapshot`, `reboot`, for a package change\n`approved_only`, and for a release upgrade `release_upgrade` and\n`third_party_repos`. A newer agent may add more."
          },
          "status": {
            "type": "string",
            "description": "`pass`, `warn` or `fail`."
          },
          "summary": {
            "type": "string",
            "description": "One sentence for a person, saying what to do when it is not a pass."
          }
        }
      },
      "PreflightHostBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "checks"
        ],
        "properties": {
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PreflightCheckBody"
            },
            "description": "What the host found, once it has reported. A failing check is an\nanswer, not a failed job."
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "job_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "The current preflight job's status: `queued`, `delivered`, `running`,\n`succeeded`, `failed`, `rejected_by_host`, `expired`, `cancelled`.\nAbsent before one is signed for this host."
          },
          "problem": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why there are no checks: the host refused the job (an agent not\npermitted `preflight` says so), or it failed."
          }
        }
      },
      "Preview": {
        "type": "object",
        "description": "The difference between two policy sets, over one fleet.",
        "required": [
          "opening",
          "closing",
          "changing",
          "unchanged",
          "dropped",
          "newly_covered"
        ],
        "properties": {
          "changing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Proposed"
            },
            "description": "Same key before and after, and something about it differs: more hosts,\nmore packages, a worse severity — or, the one that matters,\n[`Action::AutoMerge`] where it used to be [`Action::Propose`]. Carries\nthe **after** shape.\n\n⚠️ This list exists because of a bug I wrote and then tested for.\n`unchanged` originally held every shared key, so turning `propose` into\n`auto_merge` — which opens no proposal, closes none and loses no\ncoverage — made [`Preview::is_empty`] report a no-op. A portal using\nthat to decide whether to warn would have stayed silent for the single\nmost dangerous edit anybody can make to a policy."
          },
          "closing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Proposed"
            },
            "description": "Proposals that exist now and would not."
          },
          "dropped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Coverage"
            },
            "description": "⚠️ Updates a rule decides today and nothing would decide after.\n\nThe half that does not show up in proposal counts, and the one that\nleaves a fleet unpatched. An `ignore` rule counts as deciding: choosing\nto do nothing is not the same as nothing matching."
          },
          "newly_covered": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Coverage"
            },
            "description": "Updates nothing decides today and a rule would decide after."
          },
          "opening": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Proposed"
            },
            "description": "Proposals that do not exist now and would."
          },
          "unchanged": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Proposed"
            },
            "description": "Same key, same everything."
          }
        }
      },
      "PreviewBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Preview"
          },
          {
            "type": "object",
            "required": [
              "hosts_evaluated",
              "hosts_total",
              "complete",
              "would_auto_merge",
              "changes_nothing"
            ],
            "properties": {
              "changes_nothing": {
                "type": "boolean",
                "description": "Whether saving this would change anything at all."
              },
              "complete": {
                "type": "boolean",
                "description": "⚠️ `false` means the fleet was larger than one preview evaluates, so\nhost counts are lower bounds. Which *kinds* of proposal appear is still\nreliable — those come from the rules rather than from the hosts."
              },
              "hosts_evaluated": {
                "type": "integer",
                "description": "How many hosts this answer is about.",
                "minimum": 0
              },
              "hosts_total": {
                "type": "integer",
                "format": "int64",
                "description": "How many the organization has."
              },
              "would_auto_merge": {
                "type": "integer",
                "description": "How many proposals would go out with nobody looking at them, after this.",
                "minimum": 0
              }
            }
          }
        ],
        "description": "What saving a document would do: the preview endpoint's response body, and\nthe portal's live preview's, byte for byte."
      },
      "PreviewContext": {
        "type": "object",
        "description": "Everything a preview reads besides the document: what the server hands the\nportal so the portal can preview without asking again on every keystroke.",
        "required": [
          "engine",
          "live",
          "policies",
          "hosts",
          "hosts_total"
        ],
        "properties": {
          "engine": {
            "type": "string",
            "description": "[`ENGINE_VERSION`] of the server that answered. A portal whose engine\nreports a different one must not preview with it."
          },
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FleetHost"
            },
            "description": "At most the server's preview cap, oldest first."
          },
          "hosts_total": {
            "type": "integer",
            "format": "int64",
            "description": "How many hosts the organization has."
          },
          "live": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LivePolicy"
            },
            "description": "Every live policy, disabled ones included: a disabled policy still\nholds its name and can still be edited."
          },
          "policies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Policy"
            },
            "description": "The enabled ones, compiled, in evaluation order: what the engine runs."
          }
        }
      },
      "PreviewRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PolicyRequest"
          },
          {
            "type": "object",
            "properties": {
              "replaces": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The policy this document would replace, as `pol_<hex>`. Absent means a\npolicy that does not exist yet — see [`preview`]."
              }
            }
          }
        ]
      },
      "ProblemBody": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status"
        ],
        "properties": {
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "minimum": 0
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        }
      },
      "ProposalBody": {
        "type": "object",
        "required": [
          "id",
          "number",
          "title",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "status": {
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        }
      },
      "ProposalDetailBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/SummaryBody"
          },
          {
            "type": "object",
            "required": [
              "reboot",
              "changes",
              "targets",
              "targets_complete",
              "decisions"
            ],
            "properties": {
              "changes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ChangeBody"
                },
                "description": "What changes, grouped by package and by the versions involved — **not**\none entry per host per package, which on a real fleet is tens of\nthousands of them. See `db::inbox`."
              },
              "decisions": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DecisionBody"
                }
              },
              "policy": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/OriginBody"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "reboot": {
                "type": "string",
                "description": "What approving this lets it do about reboots (DAWG-103), as the rule\nsaid when the proposal was opened: `never`, `immediate` (reboot hosts\nthat need it as part of the job) or `in_window` (the same, only inside\nthe maintenance window). An agent reboots only if its own agent.toml\npermits it."
              },
              "release_upgrade": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ReleaseUpgradeBody",
                    "description": "A release upgrade's from and to (`kind` `dist_upgrade`, DAWG-153).\nAbsent on a package change, which says what it changes in `changes`."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "superseded_by": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "targets": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TargetBody"
                },
                "description": "⚠️ **`targets`, not `hosts`.** This struct flattens [`SummaryBody`],\nwhich already has a `hosts` — a count. Naming the list `hosts` too made\nthe array silently shadow the number, so the same key was an integer on\nthe list endpoint and an array on this one. Nothing failed: `serde`\nflattening has a last-one-wins rule and is happy to apply it. A\ngenerated client cannot express that, and a portal reading\n`proposal.hosts` would get whichever it was last given.\n\nFound by running `scripts/try-proposals.sh` and reading the output,\nwhich is the only place a key that collides with itself is visible."
              },
              "targets_complete": {
                "type": "boolean",
                "description": "Whether `targets` is all of them. The *count* in `hosts` is always\nexact; this list is capped."
              }
            }
          }
        ]
      },
      "ProposalListBody": {
        "type": "object",
        "required": [
          "total",
          "proposals"
        ],
        "properties": {
          "next": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as `?after=` for the next page. Absent at the end, so a client\nstops rather than asking for a page it has been told is empty."
          },
          "proposals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SummaryBody"
            }
          },
          "total": {
            "type": "integer",
            "format": "int64",
            "description": "How many match the filter, not how many are in this page."
          }
        }
      },
      "ProposalState": {
        "type": "object",
        "description": "The body every one of the three answers with.\n\nNamed for what it is rather than for the endpoint, because all three return\nit and a portal that has just clicked a button wants the same three facts\nwhichever button it was: where the proposal is now, and how the approval\ncount stands.",
        "required": [
          "id",
          "status",
          "approvals",
          "required",
          "outstanding"
        ],
        "properties": {
          "approvals": {
            "type": "integer",
            "format": "int64",
            "description": "Distinct people who have approved. A rejected proposal keeps the count\nit had: it is a record of who had agreed before somebody said no."
          },
          "id": {
            "type": "string"
          },
          "outstanding": {
            "type": "integer",
            "format": "int64",
            "description": "How many more approvals this needs before it can go ahead.\n\nZero once there are enough, and zero once there is nothing left to go\nahead with — see [`ok`]."
          },
          "required": {
            "type": "integer",
            "format": "int64",
            "description": "What the policy asked for, via `proposals.required_approvals`."
          },
          "scheduled_for": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When a proposal that is `scheduled` may start (DAWG-92).\n\nPresent only on that status, and omitted rather than null everywhere\nelse: it is not \"unknown\", it is \"does not apply\", and a portal that\nrenders a date field will render something for a null."
          },
          "status": {
            "type": "string"
          }
        }
      },
      "Proposed": {
        "type": "object",
        "description": "One proposal, as the fleet would produce it.",
        "required": [
          "dedupe_key",
          "policy_id",
          "rule_index",
          "kind",
          "action",
          "settings",
          "hosts",
          "packages"
        ],
        "properties": {
          "action": {
            "$ref": "#/components/schemas/Action",
            "description": "What would happen. `auto_merge` here is the answer to \"would this go out\nwithout anybody looking\", which is the question a preview is really for."
          },
          "dedupe_key": {
            "type": "string"
          },
          "hosts": {
            "type": "integer",
            "description": "How many hosts would be in it.",
            "minimum": 0
          },
          "kind": {
            "$ref": "#/components/schemas/UpdateKind"
          },
          "max_severity": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Severity"
              },
              {
                "type": "null"
              }
            ]
          },
          "packages": {
            "type": "integer",
            "description": "How many distinct packages, across every host.",
            "minimum": 0
          },
          "policy_id": {
            "$ref": "#/components/schemas/PolicyId"
          },
          "rollout": {
            "type": [
              "string",
              "null"
            ],
            "description": "The named rollout strategy, if the rule named one the policy defines."
          },
          "rule_index": {
            "type": "integer",
            "description": "Which rule decided it, by position. Renders as \"rule 3 of\nweb-production\" — and is the reason reordering churns keys.",
            "minimum": 0
          },
          "same_work_as": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set on an **opening** entry when a **closing** one covers exactly the\nsame work under a different key, and the other way round. Almost always\na rule that moved. See the module documentation."
          },
          "settings": {
            "$ref": "#/components/schemas/Settings",
            "description": "What else the rule decided. See [`Settings`] for why this is a struct\nrather than the one field that used to be here."
          }
        }
      },
      "ProvidersBody": {
        "type": "object",
        "required": [
          "providers"
        ],
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The external sign-in providers this deployment has credentials for:\n`github`, `google`, `microsoft`, `apple`. The sign-in page shows a button\neach."
          }
        }
      },
      "ReadinessBody": {
        "type": "object",
        "description": "One third-party repository against one release the host could move to.",
        "required": [
          "repository",
          "url",
          "target_codename",
          "target_suite",
          "status",
          "checked_at"
        ],
        "properties": {
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "detail": {
            "type": [
              "string",
              "null"
            ]
          },
          "repository": {
            "type": "string",
            "description": "As the host names it: `cloud-sdk-trixie/main`."
          },
          "status": {
            "type": "string",
            "description": "`published`, `missing`, `unknown` (see `detail`) or\n`not_release_specific` (the suite names no release and carries over)."
          },
          "target_codename": {
            "type": "string",
            "description": "The release, by apt's codename: `forky`."
          },
          "target_suite": {
            "type": "string",
            "description": "The suite that release would need: `cloud-sdk-forky`."
          },
          "url": {
            "type": "string",
            "description": "Where it is, as the agent sent it (credentials stripped on the host)."
          }
        }
      },
      "ReadinessListBody": {
        "type": "object",
        "required": [
          "readiness"
        ],
        "properties": {
          "readiness": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReadinessBody"
            }
          }
        }
      },
      "Reboot": {
        "type": "string",
        "description": "What to do about a host that needs a reboot afterwards.",
        "enum": [
          "never",
          "immediate",
          "in_window"
        ]
      },
      "RegionToken": {
        "type": "object",
        "required": [
          "token",
          "api_url",
          "expires_at"
        ],
        "properties": {
          "api_url": {
            "type": "string",
            "description": "The region's API base."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When it stops working. Ask again before then; there is no refresh."
          },
          "token": {
            "type": "string",
            "description": "`upr_…`, for `Authorization: Bearer` at `api_url`."
          }
        }
      },
      "RejectRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "`Option` so that a missing field reaches `Reason::parse` rather than\naxum's body rejection — see the note in [`reject`]. It is still\nrequired; what is optional is which of the three ways of not sending it\nthe caller chose."
          }
        }
      },
      "ReleaseBody": {
        "type": "object",
        "required": [
          "distro",
          "version",
          "is_lts"
        ],
        "properties": {
          "codename": {
            "type": [
              "string",
              "null"
            ]
          },
          "distro": {
            "type": "string",
            "description": "As `distro` on a host: `debian`, `ubuntu`."
          },
          "eol_active": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "End of ordinary vendor support, where a community or paid tier\nfollows it."
          },
          "eol_extended": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "End of extended (often paid) support."
          },
          "eol_standard": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "End of security support."
          },
          "is_lts": {
            "type": "boolean"
          },
          "released_on": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "version": {
            "type": "string",
            "description": "`13`, `24.04`."
          }
        }
      },
      "ReleaseInUseBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ReleaseBody"
          },
          {
            "type": "object",
            "required": [
              "hosts",
              "targets",
              "plans"
            ],
            "properties": {
              "hosts": {
                "type": "integer",
                "format": "int64",
                "description": "Hosts in the fleet running it."
              },
              "plans": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PlanBody"
                },
                "description": "Release upgrades from it that have not finished, newest first."
              },
              "targets": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ReleaseBody"
                },
                "description": "Releases it can be upgraded to, oldest first."
              }
            }
          }
        ]
      },
      "ReleaseRefBody": {
        "type": "object",
        "required": [
          "version"
        ],
        "properties": {
          "codename": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": "string",
            "description": "`13`, `24.04`."
          }
        }
      },
      "ReleaseUpgradeBody": {
        "type": "object",
        "description": "From which release to which.",
        "required": [
          "distro",
          "from",
          "to"
        ],
        "properties": {
          "distro": {
            "type": "string",
            "description": "As `distro` on a host: `debian`, `ubuntu`."
          },
          "from": {
            "$ref": "#/components/schemas/ReleaseRefBody"
          },
          "to": {
            "$ref": "#/components/schemas/ReleaseRefBody"
          }
        }
      },
      "ReleasesBody": {
        "type": "object",
        "description": "Every release the fleet runs.",
        "required": [
          "releases",
          "unresolved_hosts"
        ],
        "properties": {
          "releases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReleaseInUseBody"
            },
            "description": "By distribution, oldest release first."
          },
          "unresolved_hosts": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts not resolved to a known release yet. No plan can name them."
          }
        }
      },
      "ReplayBody": {
        "type": "object",
        "description": "A replay, queued.",
        "required": [
          "delivery_id"
        ],
        "properties": {
          "delivery_id": {
            "type": "string",
            "description": "The new delivery. The one replayed keeps its own record."
          }
        }
      },
      "Requirement": {
        "type": "string",
        "description": "A step that may be required before a proposal applies.",
        "enum": [
          "optional",
          "required"
        ]
      },
      "ResumedBody": {
        "type": "object",
        "description": "What resuming did.",
        "required": [
          "id",
          "status",
          "retrying"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "retrying": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts whose failed job will be signed again.",
            "minimum": 0
          },
          "status": {
            "type": "string",
            "description": "`rolling_out`."
          }
        }
      },
      "RetireRequest": {
        "type": "object",
        "properties": {
          "key": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `sk_…` of a key still retiring: the one before a rotation\n(DAWG-309), Updawg's after a hand-over to your own, or an earlier one\nof yours (DAWG-293)."
          }
        }
      },
      "RetiredBody": {
        "type": "object",
        "required": [
          "key"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "The key retired."
          }
        }
      },
      "Role": {
        "type": "string",
        "enum": [
          "viewer",
          "operator",
          "admin",
          "owner"
        ]
      },
      "RoleMappingBody": {
        "type": "object",
        "required": [
          "group",
          "role"
        ],
        "properties": {
          "group": {
            "type": "string",
            "description": "A value of the groups claim, exactly."
          },
          "role": {
            "type": "string",
            "description": "`admin`, `operator` or `viewer`."
          }
        }
      },
      "RoleRequest": {
        "type": "object",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "$ref": "#/components/schemas/Role"
          }
        }
      },
      "RollbackBody": {
        "type": "object",
        "description": "A proposal's rollback.",
        "required": [
          "hosts",
          "skipped"
        ],
        "properties": {
          "blocked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why one cannot be asked for now. Absent when it can, or when it has\nbeen."
          },
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RollbackHostBody"
            },
            "description": "The hosts it restores, each to the snapshot it took before this\nproposal changed it."
          },
          "requested": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/RollbackRequestedBody",
                "description": "Who asked, and when. Absent until somebody does."
              },
              {
                "type": "null"
              }
            ]
          },
          "skipped": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RollbackSkippedBody"
            },
            "description": "Hosts the proposal changed that it cannot restore, and why."
          }
        }
      },
      "RollbackHostBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "snapshot_id"
        ],
        "properties": {
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "job_status": {
            "type": [
              "string",
              "null"
            ],
            "description": "The rollback job's status once it is signed: `queued`, `delivered`,\n`running`, `succeeded`, `failed`, `rejected_by_host`, `expired`."
          },
          "snapshot_id": {
            "type": "string"
          }
        }
      },
      "RollbackRequestedBody": {
        "type": "object",
        "required": [
          "by",
          "email",
          "at"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "by": {
            "type": "string",
            "description": "The `usr_…` id."
          },
          "email": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "RollbackSkippedBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "reason"
        ],
        "properties": {
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "Rollout": {
        "type": "object",
        "description": "A named rollout strategy.\n\nCarried through the engine untouched: all the engine does is refuse to name\none that does not exist. What a stage *selects* is [`crate::rollout::plan`]\n(DAWG-107); advancing through them is the worker's `rollout_tick`.",
        "required": [
          "stages"
        ],
        "properties": {
          "halt_on": {
            "$ref": "#/components/schemas/HaltOn"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Stage"
            }
          }
        }
      },
      "RolloutHostBody": {
        "type": "object",
        "required": [
          "id",
          "hostname"
        ],
        "properties": {
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "job": {
            "type": [
              "string",
              "null"
            ],
            "description": "Its current job's status, or null before it has one."
          }
        }
      },
      "RolloutListBody": {
        "type": "object",
        "required": [
          "rollouts"
        ],
        "properties": {
          "rollouts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RolloutSummaryBody"
            }
          }
        }
      },
      "RolloutPlanBody": {
        "type": "object",
        "required": [
          "stages"
        ],
        "properties": {
          "halt_on": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/HaltOnBody",
                "description": "When the rollout stops itself. Null when there is no rollout."
              },
              {
                "type": "null"
              }
            ]
          },
          "halt_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why it halted, in words, when it did."
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StageBody"
            },
            "description": "In order. A stage may have no hosts: a canary stage with no canaries."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null until it starts; then running, soaking, halted, completed or cancelled."
          },
          "strategy": {
            "type": [
              "string",
              "null"
            ],
            "description": "The rollout's name in the policy, or null for every host at once."
          }
        }
      },
      "RolloutSummaryBody": {
        "type": "object",
        "description": "One rollout, for the Rollouts page.",
        "required": [
          "proposal_id",
          "number",
          "title",
          "proposal_status",
          "strategy",
          "status",
          "stages",
          "hosts",
          "succeeded",
          "failed",
          "started_at",
          "staged"
        ],
        "properties": {
          "current_stage": {
            "type": [
              "string",
              "null"
            ],
            "description": "The stage it is in, or stopped in."
          },
          "failed": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts whose current job failed, was refused or expired."
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "halt_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "hosts": {
            "type": "integer",
            "format": "int64"
          },
          "number": {
            "type": "integer",
            "format": "int32"
          },
          "proposal_id": {
            "type": "string",
            "description": "The `prp_…` id of the proposal it carries out."
          },
          "proposal_status": {
            "type": "string"
          },
          "staged": {
            "type": "boolean",
            "description": "In stages, by a strategy the rule named. `false`: every host at once,\none stage with no name."
          },
          "stages": {
            "type": "integer",
            "format": "int64"
          },
          "started_at": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "description": "Running, soaking, halted, completed or cancelled."
          },
          "strategy": {
            "type": "string",
            "description": "The rollout's name in the policy; empty for one that is not staged."
          },
          "succeeded": {
            "type": "integer",
            "format": "int64",
            "description": "Hosts whose current job succeeded."
          },
          "title": {
            "type": "string"
          }
        }
      },
      "RotateRequest": {
        "type": "object",
        "properties": {
          "from": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `sk_…` the caller believes is active. When given and no longer\ntrue, the answer is `409` and nothing is queued — a page that is a\nrotation out of date must not rotate a key its reader never saw."
          }
        }
      },
      "RotationQueuedBody": {
        "type": "object",
        "required": [
          "from"
        ],
        "properties": {
          "from": {
            "type": "string",
            "description": "The key being replaced."
          }
        }
      },
      "Rule": {
        "type": "object",
        "description": "One rule inside a policy.",
        "required": [
          "action"
        ],
        "properties": {
          "action": {
            "$ref": "#/components/schemas/Action"
          },
          "apply": {
            "$ref": "#/components/schemas/Apply"
          },
          "approval": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Approval",
                "description": "`None` means \"whatever this action implies\" — see\n[`Rule::requested_approval`]. It is an `Option` rather than a defaulted\nvalue because the sensible default depends on the action, and a rule\nthat says `action: auto_merge` and nothing else must not acquire an\napproval requirement that turns it into a proposal."
              },
              {
                "type": "null"
              }
            ]
          },
          "batch": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Batch",
                "description": "`weekly` in the example: fold everything this rule catches into one\nproposal per period rather than a stream of them."
              },
              {
                "type": "null"
              }
            ]
          },
          "match": {
            "$ref": "#/components/schemas/Match"
          },
          "preflight": {
            "$ref": "#/components/schemas/Requirement"
          },
          "reboot": {
            "$ref": "#/components/schemas/Reboot"
          },
          "rollout": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name of one of the policy's `rollouts`."
          },
          "snapshot": {
            "$ref": "#/components/schemas/Requirement"
          }
        }
      },
      "RuleBody": {
        "type": "object",
        "required": [
          "id",
          "name",
          "event_types",
          "channel_ids",
          "filter",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "channel_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`nch_…` ids."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "enabled": {
            "type": "boolean"
          },
          "event_types": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "filter": {
            "$ref": "#/components/schemas/FilterBody"
          },
          "id": {
            "type": "string",
            "description": "`nru_…`."
          },
          "name": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SavedChannelBody": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ChannelBody"
          },
          {
            "type": "object",
            "properties": {
              "signing_secret": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "`whsec_…`. See the webhook signing scheme in the API docs."
              },
              "slack_membership": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/SlackMembership",
                    "description": "For a `slack_app` channel whose Slack channel was just set: whether\nUpdawg's bot joined it. Replies in its threads reach Updawg only from\na channel the bot is in (DAWG-318)."
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          }
        ],
        "description": "A channel just saved, and — for a webhook whose configuration was just set\n— the secret its requests are signed with. ⚠️ **Shown once**: it is\nstored encrypted with the rest of the configuration and never returned\nagain. Replace the configuration to get a new one."
      },
      "ScimStatusBody": {
        "type": "object",
        "required": [
          "base_url",
          "issued"
        ],
        "properties": {
          "base_url": {
            "type": "string",
            "description": "Where the provider sends SCIM requests."
          },
          "issued": {
            "type": "boolean",
            "description": "Whether a token has been issued."
          },
          "issued_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "ScimTokenBody": {
        "type": "object",
        "required": [
          "base_url",
          "token"
        ],
        "properties": {
          "base_url": {
            "type": "string"
          },
          "token": {
            "type": "string",
            "description": "`scim_…`. Shown once; only its hash is kept."
          }
        }
      },
      "SectionBody": {
        "type": "object",
        "description": "One section of a grouped inbox.",
        "required": [
          "deleted",
          "total"
        ],
        "properties": {
          "deleted": {
            "type": "boolean",
            "description": "A policy deleted since it made these proposals."
          },
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "`pol_…` or `grp_…`, to pass as the list's `?policy=` or `?group=`.\n`null` is the section for proposals with neither: pass `none`."
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "Selector": {
        "type": "object",
        "description": "Which hosts a policy applies to.\n\n# An empty selector matches every host\n\nDeliberately, because \"the org-wide default policy\" has to be writable and\nthe natural way to write it is to say nothing. It is also the way to apply a\npolicy to the whole fleet by accident, so the schema (DAWG-86) should warn\non it and the portal's preview (DAWG-94) should show the host count before\nanybody saves.",
        "properties": {
          "groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The host is in **any** of these groups. Empty means \"any group\".",
            "uniqueItems": true
          },
          "labels": {
            "type": "object",
            "description": "The host carries **all** of these labels, with exactly these values.\nEmpty means \"any labels\".",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          }
        }
      },
      "SetHostsRequest": {
        "type": "object",
        "required": [
          "hosts"
        ],
        "properties": {
          "hosts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every static member, as `hst_…` ids. Replaces the set; label-selected\nmembers are unaffected."
          }
        }
      },
      "Settings": {
        "type": "object",
        "description": "Everything a rule decides about a proposal other than which updates are in\nit.\n\n⚠️ This exists because running the endpoint found a hole. `action` was the\nonly rule-derived field compared, so raising `min_approvers` from one to two\n— which is somebody deciding this change needs a second person — came back\nas `changes_nothing: true`. So did requiring a snapshot, or moving a\nproposal onto a different rollout.\n\nThe fields here are the ones a rule sets and a person would want to be asked\nabout. `earliest_apply_at` is deliberately **not** among them: it is\ncomputed from the clock and the maintenance window, so it differs between\ntwo runs of the same unchanged policy, and a preview that reported a change\nevery time you looked at it is a preview nobody reads.",
        "required": [
          "approval",
          "reboot",
          "preflight",
          "snapshot",
          "apply"
        ],
        "properties": {
          "apply": {
            "$ref": "#/components/schemas/Apply"
          },
          "approval": {
            "$ref": "#/components/schemas/Approval"
          },
          "preflight": {
            "$ref": "#/components/schemas/Requirement"
          },
          "reboot": {
            "$ref": "#/components/schemas/Reboot"
          },
          "snapshot": {
            "$ref": "#/components/schemas/Requirement"
          }
        }
      },
      "Severity": {
        "type": "string",
        "description": "How bad an advisory is, on one scale.\n\n# `Severity::None` is not the same as no severity\n\nThis enum is what a vendor *said*. Somewhere it is stored as a nullable\ncolumn and read back as `Option<Severity>`, and the two levels mean\ndifferent things:\n\n- `None` (the variant) — rated, and rated as not worth acting on. Ubuntu's\n  `negligible` and Debian's `unimportant` land here.\n- `Option::None` — **nobody rated it.** Debian DSAs frequently carry no\n  rating at all.\n\nCollapsing them would let a policy written `severity >= low` quietly skip\neverything nobody had got round to rating yet, which is the opposite of what\nsomebody writing that rule wants.",
        "enum": [
          "none",
          "low",
          "medium",
          "high",
          "critical"
        ]
      },
      "SeverityMatch": {
        "type": "object",
        "description": "Which severities a rule catches.\n\n# Unrated is a level, and it is not the bottom one\n\n`domain::Severity` carries a long note about why `Severity::None` and\n`Option::None` are different things: the first is \"somebody looked and said\nit does not matter\", the second is \"nobody has looked\". Debian publishes\nalmost nothing with a rating, so on a Debian host the second is common.\n\nA rule written `severity: [critical, high]` therefore does **not** catch an\nunrated update. If it did, every unassessed update on a Debian fleet would\nbe treated as critical the moment a feed was late. Writing `unrated` in the\nlist is how you ask for them, and it reads as what it is.\n\nThe failure this shape prevents is the quiet one. A rule that silently\nincluded unrated updates would auto-merge things nobody assessed; a rule\nthat silently excluded them, with no way to ask, would leave a Debian fleet\nwith no policy that matches anything. Both are wrong, and only one of them\nis visible in the YAML.",
        "properties": {
          "levels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Severity"
            },
            "uniqueItems": true
          },
          "unrated": {
            "type": "boolean",
            "description": "Spelled `unrated` in the YAML list, alongside the levels."
          }
        }
      },
      "SignUpRequest": {
        "type": "object",
        "required": [
          "name",
          "email",
          "organization"
        ],
        "properties": {
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "The person's name, as their colleagues will see it."
          },
          "organization": {
            "type": "string",
            "description": "The organization's name. Its slug is derived from it, and can be\nchanged later in Settings."
          }
        }
      },
      "SignUpVerifyRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          }
        }
      },
      "SignatureRequest": {
        "type": "object",
        "properties": {
          "signature": {
            "type": [
              "string",
              "null"
            ],
            "description": "Base64 Ed25519 signature over the job's signing bytes. Required;\noptional here only so a missing one is answered after the permission\ncheck."
          }
        }
      },
      "SignedIn": {
        "type": "object",
        "required": [
          "csrf_token"
        ],
        "properties": {
          "csrf_token": {
            "type": "string",
            "description": "The token every mutation echoes in `X-Updawg-Csrf`."
          }
        }
      },
      "SignedJobBody": {
        "type": "object",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "`queued`: its host picks it up at its next check-in."
          }
        }
      },
      "SigningKeyBody": {
        "type": "object",
        "description": "A key as the list shows it. Public halves only; there is no other kind here.",
        "required": [
          "id",
          "status",
          "public_key",
          "customer_held",
          "created_at",
          "hosts_pinned"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "customer_held": {
            "type": "boolean",
            "description": "The organization holds this key and signs in its own environment.\nUpdawg cannot sign with it, and cannot rotate it."
          },
          "endorsed_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "The `sk_…` that endorsed this one. Absent on an organization's first."
          },
          "hosts_pinned": {
            "type": "integer",
            "format": "int64",
            "description": "How many hosts said at their last check-in that they verify jobs\nagainst this key (DAWG-293). Hosts on agents too old to say are not\ncounted, so compare with the fleet before retiring a key."
          },
          "id": {
            "type": "string",
            "description": "`sk_…`."
          },
          "public_key": {
            "type": "string",
            "description": "`ed25519:` and the SPKI DER in base64 — the form an agent pins."
          },
          "status": {
            "type": "string",
            "description": "`active`, `retiring` or `retired`. One `active` at most."
          }
        }
      },
      "SlackChallengeBody": {
        "type": "object",
        "description": "What the events route answers Slack with (DAWG-319): `challenge` for\nits URL check, nothing for an event, which Slack only needs to see\nreceived.",
        "properties": {
          "challenge": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SlackChannelBody": {
        "type": "object",
        "description": "A public channel in the workspace, for the portal's channel picker.",
        "required": [
          "id",
          "name",
          "is_private",
          "is_member"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "`C…`: what a `slack_app` channel's `channel` takes."
          },
          "is_member": {
            "type": "boolean",
            "description": "Whether the app is in it already. It posts to a public channel either\nway."
          },
          "is_private": {
            "type": "boolean",
            "description": "Always `false`: only public channels are listed, because the app can\npost only to a private one it has been invited to."
          },
          "name": {
            "type": "string",
            "description": "Without the `#`."
          },
          "num_members": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "SlackChannelsBody": {
        "type": "object",
        "description": "The channels, by name.",
        "required": [
          "channels",
          "truncated"
        ],
        "properties": {
          "channels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SlackChannelBody"
            }
          },
          "truncated": {
            "type": "boolean",
            "description": "The workspace has more public channels than the 2,000 listed: one not\nhere can still be typed by name or id."
          }
        }
      },
      "SlackInstallBody": {
        "type": "object",
        "description": "Where to send the browser to install the app.",
        "required": [
          "authorize_url"
        ],
        "properties": {
          "authorize_url": {
            "type": "string",
            "description": "Slack's authorize page, with this install's state. Good for ten\nminutes, once."
          }
        }
      },
      "SlackInstallationBody": {
        "type": "object",
        "description": "The app, installed in one workspace. Never its token.",
        "required": [
          "id",
          "team_id",
          "team_name",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "id": {
            "type": "string",
            "description": "`sli_…`."
          },
          "installed_by": {
            "type": [
              "string",
              "null"
            ],
            "description": "`usr_…`, if they are still somebody."
          },
          "team_id": {
            "type": "string",
            "description": "The workspace, `T…`: what a `slack_app` channel's `team_id` names."
          },
          "team_name": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SlackInteractionReply": {
        "type": "object",
        "description": "What the interactions route answers Slack with.",
        "properties": {
          "errors": {
            "type": [
              "object",
              "null"
            ],
            "description": "For `errors`: the form's field, and what is wrong with it."
          },
          "response_action": {
            "type": [
              "string",
              "null"
            ],
            "description": "`clear` closes the reject form; `errors` keeps it open saying why."
          }
        }
      },
      "SlackLinkBody": {
        "type": "object",
        "description": "A Slack user who acts as a member when they click in Slack.",
        "required": [
          "id",
          "team_id",
          "team_name",
          "slack_user_id",
          "slack_user_name",
          "user_id",
          "created_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "id": {
            "type": "string",
            "description": "`slk_…`."
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "slack_user_id": {
            "type": "string",
            "description": "`U…`."
          },
          "slack_user_name": {
            "type": "string",
            "description": "Their name in the workspace, as Slack said it when they were linked."
          },
          "team_id": {
            "type": "string"
          },
          "team_name": {
            "type": "string"
          },
          "user_id": {
            "type": "string",
            "description": "`usr_…`: who they act as."
          },
          "user_name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SlackLinkRequestBody": {
        "type": "object",
        "description": "An offer to link a Slack account, as the person confirming it sees it:\nwhose account, in which workspace.",
        "required": [
          "team_id",
          "team_name",
          "slack_user_id",
          "slack_user_name",
          "expires_at"
        ],
        "properties": {
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "slack_user_id": {
            "type": "string"
          },
          "slack_user_name": {
            "type": "string"
          },
          "team_id": {
            "type": "string"
          },
          "team_name": {
            "type": "string"
          }
        }
      },
      "SlackMembership": {
        "type": "string",
        "description": "Whether Updawg's bot is in a Slack app channel's Slack channel, once it\nhas asked to join.",
        "enum": [
          "joined",
          "invite_needed",
          "reinstall_needed",
          "unknown"
        ]
      },
      "SlackReplyBody": {
        "type": "object",
        "description": "A reply to a slash command: Slack shows `text`, to the person who typed\nit only when `response_type` is `ephemeral`.",
        "required": [
          "response_type",
          "text"
        ],
        "properties": {
          "response_type": {
            "type": "string"
          },
          "text": {
            "type": "string"
          }
        }
      },
      "SlackSettingsBody": {
        "type": "object",
        "description": "Whether proposals may be approved from Slack (DAWG-313).",
        "required": [
          "approvals_from_slack"
        ],
        "properties": {
          "approvals_from_slack": {
            "type": "boolean",
            "description": "Off unless an admin turned it on. Rejecting, snoozing, halting and\nresuming need only a linked account."
          }
        }
      },
      "SlackSettingsRequest": {
        "type": "object",
        "required": [
          "approvals_from_slack"
        ],
        "properties": {
          "approvals_from_slack": {
            "type": "boolean"
          }
        }
      },
      "SnapshotsBody": {
        "type": "object",
        "properties": {
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "description": "The provider in use, e.g. `snapper`. Absent: none, and `reason` says\nwhy."
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "SnoozeRequest": {
        "type": "object",
        "required": [
          "until"
        ],
        "properties": {
          "until": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339, as every other timestamp this API takes or gives."
          }
        }
      },
      "SsoBody": {
        "type": "object",
        "required": [
          "domains",
          "redirect_uri"
        ],
        "properties": {
          "connection": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/SsoConnectionBody",
                "description": "Absent until one is saved."
              },
              {
                "type": "null"
              }
            ]
          },
          "domains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SsoDomainBody"
            }
          },
          "redirect_uri": {
            "type": "string",
            "description": "What to register at the provider as the sign-in redirect URI."
          }
        }
      },
      "SsoConnectionBody": {
        "type": "object",
        "required": [
          "issuer",
          "client_id",
          "groups_claim",
          "role_mappings",
          "enabled",
          "enforced",
          "updated_at"
        ],
        "properties": {
          "client_id": {
            "type": "string"
          },
          "default_role": {
            "type": [
              "string",
              "null"
            ],
            "description": "For somebody no mapping matches; absent refuses them."
          },
          "enabled": {
            "type": "boolean"
          },
          "enforced": {
            "type": "boolean"
          },
          "groups_claim": {
            "type": "string"
          },
          "issuer": {
            "type": "string"
          },
          "role_mappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoleMappingBody"
            }
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SsoConnectionRequest": {
        "type": "object",
        "required": [
          "issuer",
          "client_id"
        ],
        "properties": {
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": [
              "string",
              "null"
            ],
            "description": "Required the first time; absent afterwards keeps the stored one."
          },
          "default_role": {
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "enforced": {
            "type": "boolean"
          },
          "groups_claim": {
            "type": [
              "string",
              "null"
            ],
            "description": "Default `groups`."
          },
          "issuer": {
            "type": "string",
            "description": "The provider's issuer, exactly as its discovery document names it:\n`https://acme.okta.com`, `https://login.microsoftonline.com/<tenant>/v2.0`,\n`https://accounts.google.com`."
          },
          "role_mappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RoleMappingBody"
            }
          }
        }
      },
      "SsoDiscoverBody": {
        "type": "object",
        "required": [
          "sso",
          "enforced"
        ],
        "properties": {
          "enforced": {
            "type": "boolean",
            "description": "Whether it must: no emailed link, no GitHub."
          },
          "sso": {
            "type": "boolean",
            "description": "Whether this address signs in through its organization's provider."
          },
          "start_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where to send the browser to do that."
          }
        }
      },
      "SsoDomainBody": {
        "type": "object",
        "required": [
          "domain",
          "verified",
          "txt_name",
          "txt_value"
        ],
        "properties": {
          "domain": {
            "type": "string"
          },
          "txt_name": {
            "type": "string",
            "description": "The TXT record to publish: its name…"
          },
          "txt_value": {
            "type": "string",
            "description": "…and its value."
          },
          "verified": {
            "type": "boolean"
          },
          "verified_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "SsoDomainRequest": {
        "type": "object",
        "required": [
          "domain"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "`example.com`. Addresses at it, and only it, sign in through the\nconnection once it is verified."
          }
        }
      },
      "Stage": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "count": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Exactly this many more hosts (DAWG-107). Unlike `percent`, counted from\nthis stage, because \"the next five\" is how a count is meant.",
            "minimum": 0
          },
          "hosts": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Selector",
                "description": "Which hosts this stage covers, when it is selected by label rather than\nby proportion."
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "percent": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Bring the rollout up to this share of its hosts, **counted from the\nstart**: `25` then `100` is a quarter, then everybody else. Hosts an\nearlier stage already took count towards it.",
            "minimum": 0
          },
          "soak": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "StageBody": {
        "type": "object",
        "required": [
          "name",
          "hosts"
        ],
        "properties": {
          "finished_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "hosts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RolloutHostBody"
            }
          },
          "name": {
            "type": "string"
          },
          "soak_seconds": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "How long to wait after this stage before the next. Null for none."
          },
          "soak_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When its soak ends, while it soaks."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null until the rollout starts; then pending, running, soaking, completed, halted or cancelled."
          }
        }
      },
      "StandingBody": {
        "type": "object",
        "description": "Hosts by where their current preflight leaves them.",
        "required": [
          "not_run",
          "running",
          "ready",
          "warnings",
          "blocked",
          "no_answer"
        ],
        "properties": {
          "blocked": {
            "type": "integer",
            "format": "int64",
            "description": "A check failed."
          },
          "no_answer": {
            "type": "integer",
            "format": "int64",
            "description": "Finished without checks: refused by the agent, failed or expired."
          },
          "not_run": {
            "type": "integer",
            "format": "int64",
            "description": "No preflight signed for it yet."
          },
          "ready": {
            "type": "integer",
            "format": "int64",
            "description": "Every check passed."
          },
          "running": {
            "type": "integer",
            "format": "int64",
            "description": "Signed and not answered."
          },
          "warnings": {
            "type": "integer",
            "format": "int64",
            "description": "Nothing failed, something warned."
          }
        }
      },
      "StoppedBody": {
        "type": "object",
        "description": "What halting or cancelling did.",
        "required": [
          "id",
          "status",
          "cancelled",
          "still_out"
        ],
        "properties": {
          "cancelled": {
            "type": "integer",
            "format": "int64",
            "description": "Jobs cancelled before any host had them.",
            "minimum": 0
          },
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "`halted` or `failed`."
          },
          "still_out": {
            "type": "integer",
            "format": "int64",
            "description": "Jobs a host already holds. Not cancelled: they finish and report as\nnormal, because an agent that holds a verified job runs it."
          }
        }
      },
      "StuckBody": {
        "type": "object",
        "required": [
          "host_id",
          "hostname",
          "standing",
          "failing"
        ],
        "properties": {
          "failing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PreflightCheckBody"
            },
            "description": "The checks that failed."
          },
          "host_id": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          },
          "problem": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why there was no answer."
          },
          "standing": {
            "type": "string",
            "description": "`blocked` or `no_answer`."
          }
        }
      },
      "Summary": {
        "type": "object",
        "required": [
          "id",
          "name",
          "priority",
          "enabled",
          "version",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "type": "string"
          },
          "managed_by": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Manager",
                "description": "⚠️ `terraform`: the Terraform provider created or last saved this\npolicy, and its next `terraform apply` puts its own text back over any\nother edit. Recorded from the provider's requests and never cleared by\nan edit from anywhere else. `null` is a policy no tool claims."
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "priority": {
            "type": "integer",
            "format": "int32"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "version": {
            "type": "integer",
            "format": "int32",
            "description": "Which version is in force. Named `version` rather than\n`current_version` because from outside there is only one that matters,\nand `?version=` takes this same number."
          }
        }
      },
      "SummaryBody": {
        "type": "object",
        "required": [
          "id",
          "number",
          "kind",
          "status",
          "title",
          "known_exploited",
          "auto_merge",
          "hosts",
          "packages",
          "approvals",
          "required",
          "outstanding",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "approvals": {
            "type": "integer",
            "format": "int64"
          },
          "auto_merge": {
            "type": "boolean"
          },
          "closed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "hosts": {
            "type": "integer",
            "format": "int64"
          },
          "id": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "known_exploited": {
            "type": "boolean",
            "description": "Something it fixes is on CISA's Known Exploited Vulnerabilities list\n(DAWG-72). Shown beside the severity; it never raises it."
          },
          "max_severity": {
            "type": [
              "string",
              "null"
            ],
            "description": "`null` means nothing in this proposal was rated, which is **not** the\nsame as harmless."
          },
          "number": {
            "type": "integer",
            "format": "int32",
            "description": "The `#142` people say out loud."
          },
          "outstanding": {
            "type": "integer",
            "format": "int64",
            "description": "Zero for anything final, whatever the counts say — see\n[`db::inbox::Summary::outstanding`]."
          },
          "packages": {
            "type": "integer",
            "format": "int64",
            "description": "Distinct packages, not `proposal_items` rows."
          },
          "required": {
            "type": "integer",
            "format": "int64"
          },
          "scheduled_for": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "snoozed_until": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "description": "A status this build does not recognise is passed through as stored\nrather than hidden or guessed at. A portal should render an unknown\nstatus as unknown — it means this API is older than the thing that wrote\nthe row, which is a deployment fact worth seeing."
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TargetBody": {
        "type": "object",
        "required": [
          "id",
          "hostname"
        ],
        "properties": {
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "TestResultBody": {
        "type": "object",
        "description": "How a test send went. A channel that did not accept the message is an\nanswer, not an error: the request to try worked.",
        "required": [
          "delivered"
        ],
        "properties": {
          "delivered": {
            "type": "boolean"
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Why not, in the other side's words where there were any. Never the\ndestination."
          }
        }
      },
      "ThreadBody": {
        "type": "object",
        "required": [
          "total",
          "comments"
        ],
        "properties": {
          "comments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommentBody"
            }
          },
          "total": {
            "type": "integer",
            "format": "int64",
            "description": "Every comment on the proposal, including any outside this page."
          }
        }
      },
      "TokenBody": {
        "type": "object",
        "description": "A token as a list shows it: everything but the value.",
        "required": [
          "id",
          "name",
          "labels",
          "uses",
          "created_at",
          "usable"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "id": {
            "type": "string",
            "description": "`etk_…`. The record, not the credential."
          },
          "labels": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "max_uses": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "name": {
            "type": "string"
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "usable": {
            "type": "boolean",
            "description": "Whether an agent presenting it now would be let in: not revoked, not\nexpired, not used up. The same three conditions the gateway checks, so\nthe portal does not have to know them."
          },
          "uses": {
            "type": "integer",
            "format": "int32",
            "description": "Hosts that enrolled with it **and then checked in**. A use is charged on\nthe first check-in, not when the certificate is issued, so an attempt the\nagent refused costs nothing (DAWG-224)."
          }
        }
      },
      "UnfixedBody": {
        "type": "object",
        "required": [
          "package",
          "binary",
          "installed",
          "vulnerability",
          "description",
          "first_seen_at"
        ],
        "properties": {
          "binary": {
            "type": "boolean"
          },
          "description": {
            "type": "string"
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time"
          },
          "fixed_upstream": {
            "type": [
              "string",
              "null"
            ],
            "description": "The version that fixes it in Debian unstable. Absent: fixed nowhere."
          },
          "installed": {
            "type": "string",
            "description": "Its version on the host."
          },
          "package": {
            "type": "string",
            "description": "The source package the security tracker names — or, when `binary`, a\nbinary one."
          },
          "remote": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Remotely exploitable. Absent: not known."
          },
          "urgency": {
            "type": [
              "string",
              "null"
            ],
            "description": "`low`, `medium` or `high`. ⚠️ Absent means nobody rated it, not that\nit is harmless."
          },
          "vulnerability": {
            "type": "string",
            "description": "`CVE-…`, or the tracker's `TEMP-…` for one without a CVE yet."
          }
        }
      },
      "UnfixedListBody": {
        "type": "object",
        "required": [
          "unfixed"
        ],
        "properties": {
          "unfixed": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnfixedBody"
            }
          }
        }
      },
      "UnsignedJobBody": {
        "type": "object",
        "description": "A job built from an approved proposal, waiting for a customer-held key.",
        "required": [
          "id",
          "host",
          "key_id",
          "document",
          "created_at",
          "expires_at"
        ],
        "properties": {
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "document": {
            "type": "string",
            "description": "The job document with an empty `signature`, exactly as it will be\ndelivered once signed. Sign `updawg-job-v1`, a NUL byte, and the\ndocument's canonical JSON without `signature` — which is what\n`updawgctl sign` does, after showing what the job will do. Decide what\nto sign from this document, never from the fields beside it."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "After this it expires unsigned, and its proposal halts."
          },
          "host": {
            "$ref": "#/components/schemas/UnsignedJobHostBody"
          },
          "id": {
            "type": "string"
          },
          "key_id": {
            "type": "string",
            "description": "The `sk_…` that must sign it: the key this host pinned."
          },
          "proposal": {
            "type": [
              "string",
              "null"
            ],
            "description": "`prp_…`, when a proposal made it."
          },
          "proposal_number": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          }
        }
      },
      "UnsignedJobHostBody": {
        "type": "object",
        "required": [
          "id",
          "hostname"
        ],
        "properties": {
          "hostname": {
            "type": "string"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "UnsignedJobListBody": {
        "type": "object",
        "required": [
          "jobs"
        ],
        "properties": {
          "jobs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnsignedJobBody"
            }
          }
        }
      },
      "UpdateChannelRequest": {
        "type": "object",
        "properties": {
          "config": {
            "type": [
              "object",
              "null"
            ],
            "description": "A whole new configuration for the channel's kind, replacing the old\none. There is no merging into what is stored: nothing can read it back\nto merge into.",
            "additionalProperties": {
              "$ref": "#/components/schemas/JsonValue"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "UpdateGroupRequest": {
        "type": "object",
        "description": "Every field optional. An absent field is left alone; `null` clears\n`description` or `label_selector`.",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "label_selector": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "UpdateHostRequest": {
        "type": "object",
        "description": "Every field optional. An absent field is left alone; `null` clears\n`display_name` or `notes`. `labels` replaces the whole set.",
        "properties": {
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "labels": {
            "type": [
              "object",
              "null"
            ],
            "description": "⚠️ The **whole** set, not a merge. A merge could never remove a label,\nand a label is a selector: one left behind keeps the host in a group.",
            "additionalProperties": {
              "type": "string"
            },
            "propertyNames": {
              "type": "string"
            }
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "UpdateKind": {
        "type": "string",
        "description": "`Ord` is derived so this can key an ordered collection — the policy engine\ngroups proposals by kind in a `BTreeMap` and needs a total order to produce\nthe same output twice. The order itself is the declaration order and carries\nno meaning; nothing should read severity into it.",
        "enum": [
          "security",
          "patch",
          "kernel",
          "dist_upgrade"
        ]
      },
      "UpdateRequest": {
        "type": "object",
        "properties": {
          "agent_auto_update": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Keep agents on the stable channel without anybody approving each\nupdate (DAWG-46). When stable moves, an agent update is opened and\napproved on your authority, for every host behind it whose agent.toml\npermits `self_update`. It stays yours: if you stop administering the\norganization, nothing more is signed until somebody turns it on again."
          },
          "audit_retention_days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Days to keep the audit log, 7 up to what the plan keeps\n(`audit_retention_max_days`), or `null` for the plan's whole window\n(DAWG-160). Owner only. Shortening it deletes the older entries at the\nnext nightly run, and nothing brings them back."
          },
          "eol_lead_days": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Days before a release's support ends to raise `release.eol`, each 1\nto 730, at most six (DAWG-70). Stored longest first without repeats.\nEmpty leaves only the alert when support has ended."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absent means \"leave it alone\", which is not the same as an empty string."
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "stale_after_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Minutes without a check-in before a host is marked stale, 5 to 10,080\n(DAWG-62). Set it above your longest expected outage — a reboot, a\nmaintenance window — or every one of them marks hosts stale."
          }
        }
      },
      "UpdateRuleRequest": {
        "type": "object",
        "properties": {
          "channel_ids": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "event_types": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            }
          },
          "filter": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/FilterBody"
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "UpdatedGroupBody": {
        "type": "object",
        "required": [
          "group",
          "policies_naming_old_name"
        ],
        "properties": {
          "group": {
            "$ref": "#/components/schemas/HostGroupBody"
          },
          "policies_naming_old_name": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Live policies whose selector named the group's **old** name, and so now\nmatch nothing of it. A policy selects a group by name. Empty unless the\nname changed."
          }
        }
      },
      "UpdatesBody": {
        "type": "object",
        "required": [
          "total",
          "security",
          "requiring_reboot"
        ],
        "properties": {
          "requiring_reboot": {
            "type": "integer",
            "format": "int64",
            "description": "Updates that will leave the host needing a reboot — distinct from\n`reboot_required`, which is whether it needs one now."
          },
          "security": {
            "type": "integer",
            "format": "int64"
          },
          "total": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "UsageBody": {
        "type": "object",
        "required": [
          "from",
          "to",
          "days",
          "host_days"
        ],
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageDayBody"
            },
            "description": "Every day with a recorded count, oldest first. A day nothing checked\nin on has no row and costs nothing."
          },
          "estimate_pence": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "`host_days` on this plan's list price, in pence, for an organization\nwith a live subscription. An estimate: Stripe's invoice is the bill.",
            "minimum": 0
          },
          "from": {
            "type": "string",
            "format": "date",
            "description": "The first and last day of the month asked about."
          },
          "host_days": {
            "type": "integer",
            "format": "int64",
            "description": "The sum of `days`: what the month has used so far."
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "today_so_far": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Hosts that have checked in today so far, not yet in `days`. Only for\nthe current month."
          }
        }
      },
      "UsageDayBody": {
        "type": "object",
        "required": [
          "day",
          "active_hosts",
          "reported"
        ],
        "properties": {
          "active_hosts": {
            "type": "integer",
            "format": "int32",
            "description": "Hosts that checked in during the day, UTC: the day's billable count."
          },
          "day": {
            "type": "string",
            "format": "date"
          },
          "reported": {
            "type": "boolean",
            "description": "Sent to Stripe."
          }
        }
      },
      "Validation": {
        "type": "object",
        "required": [
          "valid",
          "errors"
        ],
        "properties": {
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PolicyProblem"
            },
            "description": "⚠️ **At most one today.** serde stops at the first thing it cannot read,\nso there is no second error to report — collecting them all needs a\nparser that keeps going, which this one does not. An array rather than a\nsingle object so that the shape does not have to change when it can."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "What the document says it is, when it is anything. Absent rather than\nnull-and-empty on a failure, because a half-populated body invites a\nclient to read fields that mean nothing."
          },
          "priority": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "rules": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "valid": {
            "type": "boolean"
          }
        }
      },
      "VerifyRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string"
          }
        }
      },
      "WindowBody": {
        "type": "object",
        "description": "A maintenance window, as a policy's compiled form has one.",
        "required": [
          "start",
          "duration",
          "timezone"
        ],
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`mon` … `sun`. Empty is every day."
          },
          "duration": {
            "type": "integer",
            "format": "int64",
            "description": "Seconds."
          },
          "start": {
            "type": "string",
            "description": "Local wall-clock time in `timezone`, `HH:MM:SS`."
          },
          "timezone": {
            "type": "string",
            "description": "An IANA name: `Europe/London`."
          }
        },
        "additionalProperties": false
      }
    }
  },
  "tags": [
    {
      "name": "session",
      "description": "Signing in, and who is signed in."
    },
    {
      "name": "organizations",
      "description": "Tenants, their members and their invitations."
    },
    {
      "name": "enrollment",
      "description": "Enrollment tokens: how a host gets into a fleet."
    },
    {
      "name": "notifications",
      "description": "Where notifications go — channels, whose credentials are stored encrypted and never returned — and the rules that choose which events go to which."
    },
    {
      "name": "groups",
      "description": "Host groups: static members, a label selector, or both."
    },
    {
      "name": "audit",
      "description": "The organization's record of every change made to it."
    },
    {
      "name": "compliance",
      "description": "Patch latency and the fleet's standing against the organization's patch targets, as evidence for SOC 2 and ISO 27001."
    },
    {
      "name": "signing-keys",
      "description": "The keys an organization's jobs are signed with, rotating them, and handing signing over to the organization's own key."
    },
    {
      "name": "sso",
      "description": "Single sign-on with the organization's own OpenID Connect provider: the connection, and the domains it covers."
    },
    {
      "name": "hosts",
      "description": "The fleet: what is in it and what one host looks like."
    },
    {
      "name": "advisories",
      "description": "What the fleet is exposed to, and where."
    },
    {
      "name": "proposals",
      "description": "What Updawg suggests doing, and deciding about it."
    },
    {
      "name": "policies",
      "description": "The rules that decide what gets proposed."
    },
    {
      "name": "releases",
      "description": "The fleet by release, and planning a release upgrade."
    },
    {
      "name": "events",
      "description": "A live stream of hints that something changed, for the portal to refetch."
    },
    {
      "name": "billing",
      "description": "The plan, the subscription behind it, and Stripe."
    },
    {
      "name": "slack",
      "description": "The Slack app: installing it in a workspace, and the Slack users linked to members (ADR 0009)."
    }
  ]
}